一、函数的基本语法与特性
初中数学函数定义:一般的,在一个变化过程中,如果有两个变量x和y,并且对于x的每一个确定的值,y都有唯一确定的值与其对应,那么我们就把x称为自变量,把y称为因变量,y是x的函数。自变量x的取值范围叫做这个函数的定义域
例如 y = 2 * x
函数是什么?
函数一词来源于数学,但编程中的「函数」概念,与数学中的函数是有很大不同的,编程中的函数在英文中也有很多不同的叫法。在BASIC中叫做subroutine(子过程或子程序),在Pascal中叫做procedure(过程)和function,在C中只有function,在Java里面叫做method。
python中函数定义:
函数是指将一组语句的集合通过一个名字(函数名)封装起来,要想执行这个函数,只需调用其函数名即可。
你可以定义一个由自己想要功能的函数,以下是简单的规则:
- 函数代码块以 def 关键词开头,后接函数标识符名称和圆括号 ()。
- 任何传入参数和自变量必须放在圆括号中间,圆括号之间可以用于定义参数。
- 函数的第一行语句可以选择性地使用文档字符串—用于存放函数说明。
- 函数内容以冒号起始,并且缩进。
- return [表达式] 结束函数,选择性地返回一个值给调用方。不带表达式的return相当于返回 None。
特性:
- 减少重复代码
- 使程序变的可扩展
- 使程序变得易维护
python中函数定义方法: def test(x): "The function definitions" x+=1 return x def:定义函数的关键字 test:函数名 ():内可定义形参 "":文档描述(非必要,但是强烈建议为你的函数添加描述信息) x+=1:泛指代码块或程序处理逻辑 return:定义返回值 调用运行:可以带参数也可以不带 函数名()
补充:
1.编程语言中的函数与数学意义的函数是截然不同的俩个概念,编程语言中的函数是通过一个函数名封装好一串用来完成某一特定功能的逻辑,数学定义的函数就是一个等式,等式在传入因变量值x不同会得到一个结果y,这一点与编程语言中类似(也是传入一个参数,得到一个返回值),不同的是数学意义的函数,传入值相同,得到的结果必然相同且没有任何变量的修改(不修改状态),而编程语言中的函数传入的参数相同返回值可不一定相同且可以修改其他的全局变量值(因为一个函数a的执行可能依赖于另外一个函数b的结果,b可能得到不同结果,那即便是你给a传入相同的参数,那么a得到的结果也肯定不同)
2.函数式编程就是:先定义一个数学函数(数学建模),然后按照这个数学模型用编程语言去实现它。至于具体如何实现和这么做的好处,且看后续的函数式编程。
二、函数和过程
过程定义:过程就是简单特殊没有返回值的函数
这么看来我们在讨论为何使用函数的的时候引入的函数,都没有返回值,没有返回值就是过程,没错,但是在python中有比较神奇的事情
def test01(): msg='hello' print msg def test02(): msg='hello WuDa' print msg return msg t1=test01() t2=test02() print 'from test01 return is [%s]' %t1 print 'from test02 return is [%s]' %t2
总结:当一个函数/过程没有使用return显示的定义返回值时,python解释器会隐式的返回None。所以在python中即便是过程也可以算作函数。
def test01(): pass def test02(): return 0 def test03(): return 0,10,'hello',['ax','lb'],{'WuD':'lb'} t1=test01() t2=test02() t3=test03() print 'from test01 return is [%s]: ' %type(t1),t1 print 'from test02 return is [%s]: ' %type(t2),t2 print 'from test03 return is [%s]: ' %type(t3),t3
总结:
返回值数=0:返回None
返回值数=1:返回object
返回值数>1:返回tuple
三、函数参数
1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只在函数内部有效。函数调用结束返回主调用函数后则不能再使用该形参变量
2.实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使参数获得确定值
3.位置参数和关键字参数(标准调用:实参与形参位置一一对应;关键字调用:位置无需固定)
位置参数: 在调用函数时,Python必须将每个实参都关联到函数定义的一个形参中,最简单的关联方式就是基于实参的顺序。
关键字参数 :传递给函数的是键值对。由于在实参中的将名称和值关联起来,所以在传入时无需考虑顺序。
def hello(name1,name2): pass hello("lian","zong") #位置实参 hello(name1="lian",name2="zong") # 关键字参数
#位置参数和关键字参数混合使用时: #1、位置参数必须写在关键字参数的左边 #2、同一个参数不能两次或者多次传值,只能传一次 def hello(name,age,height): pass hello("lian",age = 20,height = 175) #正确的混合方式 hello(name = "lian",20,height = 175)#错误的方式,位置参数必须放在关键字左边,否则报错
4.默认参数
def stu_register(name,age,country,course): print("----注册学生信息------") print("姓名:",name) print("age:",age) print("国籍:",country) print("课程:",course) stu_register("王山炮",22,"CN","python_devops") stu_register("张叫春",21,"CN","linux") stu_register("刘老根",25,"CN","linux")
发现 country 这个参数 基本都 是"CN", 就像我们在网站上注册用户,像国籍这种信息,你不填写,默认就会是中国, 这就是通过默认参数实现的,把country变成默认参数非常简单
def stu_register(name,age,course,country="CN"):
5.参数组
-
* 的作用其实就是把序列 args 中的每个元素,当作位置参数传进去。
-
** 的作用则是把字典 kwargs 变成关键字参数传递。
def calc(x,y,*args): res =x+y print(x,y,args)#*args-->多于的参数,位置参数传入,以元组的形式接收 calc(1,2,7,8,6) calc(2,3,{"name":"al"}) #即使传入字典,字典当成整体也会以元组的方式被接收 calc(3,4,["al","James"],"hello world") calc(3,4,*["al","James"]) #相当于该列表遍历,逐个添加至列表并且转为元组 calc(3,4,*"al")
def calc(x,y,**kwargs): res =x+y #print(x,y) print(x,y,kwargs)#**kwargs-->多于的参数,位置参数传入,以字典的形式接收 return res calc(x=1,y=3,name="al") calc(1,2,**{"name":"Amanda"})
四、局部变量和全局变量
name='lhf' def change_name(): print('我的名字',name) change_name() def change_name(): name='帅' print('我的名字',name) change_name() print(name) def change_name(): global name name='帅' print('我的名字',name) change_name() print(name)
五、嵌套函数
#嵌套函数 def func1(): print('func1') def func2(): print('func2') func1()
结果:func1
为什么函数func2没有被执行?
任意一个函数定义完成之后,如果没有人通过名字调用它,就永远不会执行
那如何调用func2?
def func1(): print('func1') def func2(): print('func2') func2()
func1()
结果:
func1
func2
函数引用变量的时候是从该函数内部一层一层的向外找,还有一点值得注意的是,要遵循代码的执行顺序,想要被调用的变量不能在被执行函数的下面。
六、前向引用之“函数即变量”
def foo(): print('from foo') bar() foo()
运行结果:
NameError: name 'bar' is not defined
def foo(): print('from foo') bar() def bar(): print('from bar') foo()
运行结果:
from foo
from bar
七、递归
在函数内部,可以调用其他函数。如果一个函数在内部调用自身本身,这个函数就是递归函数。
def calc(n): print(n) if int(n/2) ==0: return n return calc(int(n/2)) calc(10) 输出: 10 5 2 1
递归特性:
1. 必须有一个明确的结束条件
2. 每次进入更深一层递归时,问题规模相比上次递归都应有所减少
3. 递归效率不高,递归层次过多会导致栈溢出(在计算机中,函数调用是通过栈(stack)这种数据结构实现的,每当进入一个函数调用,栈就会加一层栈帧,每当函数返回,栈就会减一层栈帧。由于栈的大小不是无限的,所以,递归调用的次数过多,会导致栈溢出)
八、匿名函数(匿名函数就是不需要显式的指定函数)
#这段代码 def calc(n): return n**n print(calc(10)) #换成匿名函数 calc = lambda n:n**n print(calc(10))
九、返回值
要想获取函数的执行结果,就可以用return语句把结果返回
注意:
- 函数在执行过程中只要遇到return语句,就会停止执行并返回结果,so 也可以理解为 return 语句代表着函数的结束
- 如果未在函数中指定return,那这个函数的返回值为None
十、函数式编程介绍
函数是Python内建支持的一种封装,我们通过把大段代码拆成函数,通过一层一层的函数调用,就可以把复杂任务分解成简单的任务,这种分解可以称之为面向过程的程序设计。函数就是面向过程的程序设计的基本单元。
函数式编程中的函数这个术语不是指计算机中的函数(实际上是Subroutine),而是指数学中的函数,即自变量的映射。也就是说一个函数的值仅决定于函数参数的值,不依赖其他状态。比如sqrt(x)函数计算x的平方根,只要x不变,不论什么时候调用,调用几次,值都是不变的。
Python对函数式编程提供部分支持。由于Python允许使用变量,因此,Python不是纯函数式编程语言。
十一、高阶函数
变量可以指向函数,函数的参数能接收变量,那么一个函数就可以接收另一个函数作为参数,这种函数就称之为高阶函数。
def add(x,y,f): return f(x) + f(y) res = add(3,-6,abs) print(res)
十二、内置函数
字典的运算:最小值,最大值,排序 salaries={ 'egon':3000, 'alex':100000000, 'wupeiqi':10000, 'yuanhao':2000 } 迭代字典,取得是key,因而比较的是key的最大和最小值 >>> max(salaries) 'yuanhao' >>> min(salaries) 'alex' 可以取values,来比较 >>> max(salaries.values()) 100000000 >>> min(salaries.values()) 2000 但通常我们都是想取出,工资最高的那个人名,即比较的是salaries的值,得到的是键 >>> max(salaries,key=lambda k:salary[k]) 'alex' >>> min(salaries,key=lambda k:salary[k]) 'yuanhao' 也可以通过zip的方式实现 salaries_and_names=zip(salaries.values(),salaries.keys()) 先比较值,值相同则比较键 >>> max(salaries_and_names) (100000000, 'alex') salaries_and_names是迭代器,因而只能访问一次 >>> min(salaries_and_names) Traceback (most recent call last): File "<stdin>", line 1, in <module> ValueError: min() arg is an empty sequence sorted(iterable,key=None,reverse=False)