def 函数名([参数1][,参数2][,参数3]...): [函数语句]#函数语句和return语句不能同时省略 [return [返回值]]#return后面可以没有返回值
在Python中,所有语句都是实时执行的,不存在C/C++的编译过程,def也是一条可执行语句,定义一个函数。所以函数的调用必须在定义之后
>>> def add(a,b): ... return a+b ... >>> add <function add at 0x0000000005DAB730> >>> add(1,2) 3 >>> x=add >>> x(1,2) 3 >>> def nullFun(a,b): ... return ... >>> nullFun(1,2) >>>
调用函数时,参数表中提供的参数成为实际参数,简称实参。在Python中,变量保存的是对象的引用,类似于C/C++中的指针。实参传递给形参就是将对象引用赋值给形参。
函数的多态性
多态是面向对象的一个特点,指同一个行为针对不同对象可能会得到不同的结果。Python中的对象无类型属性,变量可饮用各种不同类型的对象。同一个函数,传递的实际参数类型不同时,可获得不同的结果,体现了多态性。例如:
>>> def add(a,b): ... return a+b ... >>> add(1,3) 4 >>> add(1,1.5) 2.5 >>> add('abc', 'def') 'abcdef' >>> add([1,3],[2,4]) [1, 3, 2, 4]
参数赋值传递
Python允许以形参赋值的方式,指定将实参传递给形参。例如:
>>> def add(a,b):return a+b ... >>> add(a='ab',b='cd') 'abcd' >>> add(b='ab',a='cd') 'cdab'
可以看出,采用这种方式时,以形参赋值为准,参数顺序可以忽略。
参数传递与共享引用
>>> def f(x): x=100 ... >>> a=10 >>> f(a) >>> a 10
可以看出在函数中重新赋值a,并不会影响函数外的a,因为Python中的赋值时建立变量到对象的引用。重新赋值时,意味着形参引用了新的对象,原来的引用已经作废。
小心使用可变参数
>>> def f(a): ... a[0]='abc' ... >>> x=[1,2] >>> f(x) >>> x ['abc', 2]
当使用可变参数时,如列表、字典等,若在函数中修改形参,因为是共享引用,通过实参也获得修改后的对象。如上。
如果不希望在函数中的修改影响函数外的变量,也可以显示的避免。
例如列表,可以使用列表的拷贝作为实参。如:
>>> def f(a): ... a[0]='abc' ... >>> x=[1,2] >>> f(x[:]) >>> x [1, 2]
也可以在函数内对列表进行拷贝,实参仍使用变量。例如
>>> def f(a): ... a=a[:] ... >>> def f(a): ... a=a[:] ... a[0]='abc' ... >>> x=[1,2] >>> f(x) >>> x [1, 2]
有默认值的参数
如c++
传递任意个数的参数
定义参数时,参数名前使用“*”,表示可以接受任意个参数(包括0个),这些参数保存在一个元组中。
>>> def add(a,*b,c): ... print(c) ... s=a ... for x in b: ... s+=x ... return s ... >>> add(1,2) 3 >>> add(1,2,3) 6 >>> add(1) 1
如果带“*”参数的后面仍然有参数,则必须通过赋值传递。如上。
函数嵌套定义
内部定义的函数作用域为函数内
>>> def add(a,b): ... def getsum(x): ... s=0 ... for n in x: ... s+=ord(n) ... return s ... return getsum(a)+getsum(b) ... >>> add('12', '34') 202
lambda函数
lambda函数也成为表达式函数,用于定义一个匿名函数,可以将该函数赋值给变量,通过变量调用。lambda函数定义的基本格式如下。
lambda 参数:表达式
如:
>>> add=lambda a,b:a+b >>> add(1,2) 3 >>> add('ab','cd') 'abcd'
递归函数
如C/C++
函数列表
Python允许将函数作为列表对象,然后列表索引来调用函数。如:
>>> add=lambda a,b:a+b #通过lambda简历 >>> add(1,2) 3 >>> add('ab','cd') 'abcd' >>> >>> >>> d=[lambda a,b:a+b,lambda a,b:a*b] >>> d[0](1,3) 4 >>> d[1](1,3) 3 >>> >>>#通过def建立 >>> def add(a,b): ... return a+b ... >>> def fac(n): ... if n==0: ... return 1 ... else: ... return n*fac(n-1) ... >>> d=[add,fac]#建立包含函数列表的列表对象 >>> d[0](1,2) 3 >>> d[1](5) 120 >>> d=(add,fac)#建立包含函数列表的元组对象 >>> d[0](2,3) 5 >>> d[1](5) 120
提示:函数列表的实质就是在元组、列表和字典等序列中简历函数对象的引用,然后通过索引来调用函数。
变量作用域就是变量的可访问范围,也可称为命名空间。在第一次给变量赋值时,Python创建变量,第一次给变量赋值的位置决定了变量的作用域。
作用域由大到小分为:内置作用域>文件作用域>函数嵌套作用域>本地作用域
本地作用域:不包含其他函数定义的函数的内部成为本地作用于。函数内通过赋值创建的变量,函数参数都属于本地作用域
函数嵌套作用域:包含了其他函数定义的函数的内部成为函数嵌套作用域
文件作用域:程序文件(也称模块文件)的内部为文件作用域
内置作用域:最顶层,包含了python各种预定义变量和函数的作用域成为内置作用域。
内置作用域和文件作用域有时都被成为全局作用域(变量称为全局变量),函数嵌套作用域优势也成为本地作用域(变量成为本地变量)。
作用域外的变量与作用域内的变量名称相同时,遵循“本地”优先原则,此时外部的作用域被屏蔽--成为作用隔离原则。与C/C++类似。但与C/C++不同的是,在更小作用域整体里,定义该重复变量之前的范围,程序是检测不到那个大作用域的变量的。
>>> a=10 >>> def show(): ... print('a=',a) ... a=100 ... print('a=',a) ... >>> show() Traceback (most recent call last): File "" , line 1, in <module> File "" , line 2, in show UnboundLocalError: local variable 'a' referenced before assignment
使用global语句可以在函数内部声明全局变量。全局变量增大了代码维护调试难度,不建议用。
>>> a=10 >>> def show(): ... global a#有用吗?前面不是定义了个全局的a吗? ... a+=1 ... print('a=',a) ... >>> show() a= 11 >>> show() a= 12 >>> show() a= 13
作用域隔离原则同样适用于函数内部的嵌套函数。在嵌套函数内使用与上层函数本地变量同名的变量时,若该变量没有被赋值,则该变量就是上层函数的本地变量。如:
>>> def test(): ... a=10 ... def show(): ... print('in show(),a=',a) ... show() ... print('in test(),a=',a) ... >>> test() in show(),a= 10 in test(),a= 10
稍微修改
>>> def test(): ... a=10 ... def show(): ... a=100 ... print('in show(),a=',a) ... show() ... print('in test(),a=',a) ... >>> test() in show(),a= 100 in test(),a= 100
若想这个a与上一层a为同一个,则需要加一句nonlocal a,来声明变量是外部的本地变量。
>>> def test(): ... a=10 ... def show(): ... nonlocal a ... a=100 ... print('in show(),a=',a) ... show() ... print('in test(),a=',a) ... >>> test() in show(),a= 100 in test(),a= 100