函数是对能完成某种功能的语句块的封装。由函数名、参数列表和多语句构成的语句块组成,定义方式以下:python
def func_name(argrs):
语句块
说明:数组
ret = func_name(args)
说明:app
>>> print(1,2,sep='\n') 1 2
>>> a = 1, b= 2
>>> print(a, b, sep='\n')
1
2
函数返回函数
形参中可能包含四种参数(排序分前后):位置参数、可变位置参数、keyword-only参数、可变keyword-only参数。ui
>>> def f4(a, b):
... print('a =', a)
... print('b =', b)
...
>>> c, d = 1, 2
>>> f4(c, d) #对应位置匹配,至关于实参分别为对应位置形参变量赋值,a=c, b=d
a = 1
b = 2
>>> f4(b = d, a = c)
a = 1
b = 2
注意:由于参数是经过赋值传递的,全部实参和形参从某种意义上讲是在共享对象。若是传递的是可变对象,那么函数对形参的原地修改可能会影响到实参。 spa
>>> def f5(*, a, b): #‘*’的意义在于,在语法上将a、b定义为keyword-only参数
... return a, b
...
>>> f5(1,2)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: f1() takes 0 positional arguments but 2 were given
#keyword-only参数不能经过位置进行匹配
>>> f5(b=1, a=2)
(2, 1)
>>> def f5(*args, a, b): ... print('args =', args) ... print('a =', a) ... print('b =', b) ...
>>> c = 3
>>> d = 4 >>> f5(1, 2, a=c, b=d) args = (1, 2) a = 3 b = 4
#形参中的*args参数收集任意多个未匹配的位置参数到一个tuple。
>>> f2(a=1, 2, b=4)
File "<stdin>", line 1
SyntaxError: positional argument follows keyword argument
#实参的位置参数必须位于关键字参数以前
形式上,位置参数和keyword-only参数没有区别,为了定义keyword-only参数必须将其放到*或者*args后。code
>>> def f6(p1, p2=0, *, k1=[], k2): #定义中p2 和 k1有默认值,传参的时候能够缺省,可是p1和k2必须有相应的参数传入,不然会报错 ... print('p1 =', p1) ... print('p2 =', p2) ... print('k1 =', k1) ... print('k2 =', k2) ...
>>> f6(1, k2=3) #1位置匹配到形参中的p1, k2匹配形参中的k2, p2 和 k1使用定义中规定的默认值 p1 = 1 p2 = 0 k1 = [] k2 = 3
>>> f6(p1 = 1, p2 = 2). #位置参数也能够经过name = value的形式传递,经过name进行匹配,传参顺序无关 Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: f6() missing 1 required keyword-only argument: 'k2'
#缺乏keyword-only参数:‘k2’
>>> f6(1,p2 = 2, k2 = 3) # 1经过位置匹配传给p1, p2 和 k2分别经过name匹配传递,没有k1对应的实参传入,使用默认值 p1 = 1 p2 = 2 k1 = [] k2 = 3
>>> f6(1,2, k2 = 3, k1 = 4) # 4个形参都有对应实参传入,因此不须要使用默认值 p1 = 1 p2 = 2 k1 = 4 k2 = 3
>>> def f7(a=1, b): ... return a,b ... File "<stdin>", line 1 SyntaxError: non-default argument follows default argument
实参(位置参数和关键字参数)和形参(位置参数、可变位置参数、keyword-only参数、可变keyword-only参数)之间的匹配顺序能够这样理解:对象
默认参数是在def语句运行时评估并保存的,而不是在函数调用时。在内部讲,python会将全部默认参数组合生成一个元组对象,做为函数的一个属性(__defaults__)保存。由于属性是附加到函数自己的,全部对该函数的调用都使用了同一个对象,因此对可变默认参数的修改要慎重。blog
>>> def saver(x = []):
... x.append(1)
... print(x)
...
>>> saver.__defaults__ #对象属性的查看方式,应用该对象的变量名加点加属性名
([],)
>>> saver()
[1]
>>> saver.__defaults__
([1],)
>>> saver()
[1, 1]
若是这不是你所想要的行为能够将默认参数值的表达式移到函数体内:排序
>>> def saver(x=None): ... x = x or [] #若是没有参数传入的话,x默认为None,or运算返回后面的空列表 ... x.append(1) ... print(x) ... >>> saver() [1] >>> saver() [1]
or运算,从左到右计算表达式返回第一个遇到的真值,若是全部值都为False,那么返回最后一个值。若是传入的x参数为0或者空列表或者空集合等,那么就都会替换为空列表[]了,这可能也不符合预期,咱们可使用if语句:
>>> def saver(x=None): ... if x is None: ... x = [] ... x.append(1) ... print(x)