函数的参数
转瞬一年,又快到动物们交...(*/∇\*),嘛~拖更无限好...
咳咳,去年说的函数的定义时有包含参数,只要把参数的名字和位置确定下来,函数的 接口 定义就完成了。函数调用者只需知道如何传递正确的参数,以及函数将返回什么样的值就够了,内部的复杂逻辑被封装,无需了解。
位置参数
def power(x):
return x * x
对于上述的 power(x) 函数,参数 x 就是一个位置参数。位置参数可以有多个。例如将上述程序做如下修改,调用的时候,传入两个值按照位置顺序依次赋予 x 和 n :
def power(x, n):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
默认参数
重新定义的 power(x,n) 可以用在计算任意 n 次方,但是旧的代码调用失效了,如果只是输入一个参数,会使得旧代码因缺少一个参数而无法正常调用:
>>> power(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: power() missing 1 required positional argument: 'n'
如果想要旧代码那种,输入一个参数,自动获得平方结果。就可以使用默认参数了:
def power(x,n=2):
s= 1
while n > 0:
n = n-1
s = s * x
return s
之后,运行:
>>>power(5)
>>>25
设置默认参数需要注意几点:
一、必选参数在前,默认参数在后,否则 Python 解释器会报错;
二、函数变化大的参数放前面,小的就可以作为默认参数放在后头;
设置默认参数可以降低函数的难度,复杂点的函数也可以放多几个参数,也方便用户使用。eg:
def enroll(name,gender,age=6,city='beijing'):
print('name:',name)
print('gender:',gender)
print('age:',age)
print('city:',city)
运行:
>>> enroll('Lily','F')
name: Lily
gender: F
age: 6
city: beijing
不按照顺序给参数:
>>> enroll('Lala','C','city=shanwei')
但是默认参数使用不当,也会出现不少bug,例如:
def add_end(L=[]):
L.append('END')
return L
此程序在正常调用时是传入一个 list,在其末尾处放入个 END,再返回,例如[1,2,3],返回[1,2,3,'END']。但是如果使用默认参数调用时,第一次正常,但是多调用几次就可以发现...
原因很简单,默认参数指向了可变对象,所以 L 好像记住了 'END'。所以定义默认参数还需要注意,默认参数必须指向不可变对象(str/None等)!
修改法:
def add_end(L=None):
if L is None:
L=[]
L.append('END')
return L
可变参数
可变参数,参数的数量可以任意个。以数学题为例,给定一组数字a,b,c...,要求计算出它们的平方和。方法之一可以将这组数字作为 list 或者 tuple 参数传入:
def calc(numbers):
sum = 0
for n in numbers:
sum=sum+nn
return sum
但是每次得先把这组数据组成 list 或者 tuple,例如calc([1,2,3])是略微麻烦的。可以稍微改动一下:
def calc(numbers):
sum = 0
for n in numbers:
sum=sum+n*n
return sum
代码基本不变,但是加了个 ,就可以直接传入所需要的数据参数了,calc(1,2,3)。
而如果已经有了一个 list 或 tuple 数据参数,例如nums=[1,2,3],导入可不需要 calc(nums[0],nums[1],nums[2]),只需要在调用时输入 calc(*nums) 即可。
nums 表示把 nums 这个 list 的所有元素作为可变参数传进去。
关键字参数
可变参数允许传入任意个参数,这些参数在函数调用时自动组装成一个 tuple 。而关键字参数是允许传入任意个参数,然后在调用函数的时候自动组装成一个 dict。
eg:
def person(name,age,**kw):
print('name:',name,'age:',age,'other:',kw)
调用:
>>> person('小明',20)
name: 小明 age: 20 other: {}
>>> person('小红','18',性别='男',QQ签名='小明滚犊子,我们不会在一起的')
name: 小红 age: 18 other: {'性别': '男', 'QQ签名': '小明滚犊子,我们不会在一起的'}
关键字参数可以用在例如用户注册的场景,需要输入的位置参数是必填选项,关键字参数是可选,例如备注等。
当然跟可变参数一样,可以先组装个 dict ,然后再导入:
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, city=extra['city'], job=extra['job'])
也可以用可变参数类似的方法 **extra,把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict,注意kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra。
命名关键字
函数的调用者可以传入任意不受限制的关键字参数,但至于传入了哪些就需要在函数内部通过 kw 检查。
def person(name, age, **kw):
if 'city' in kw:
# 有city参数
pass
if 'job' in kw:
# 有job参数
pass
print('name:', name, 'age:', age, 'other:', kw)
但是如果要限制关键字参数的名字,就可以命名关键字。例如只接收 city 和 job 作为关键字参数,可以由缺省值,简化调用:
def person(name,age,*,job='teacher',city):
print(name,age,job,city)
如果定义中已经有一个可变参数,后面跟着的命名关键字就不再需要一个特殊分隔符 * ,但是没有可变参数的时候必须有分隔符 * :
def person(name,age,*args,job,city):
print(name,age,args,job,city)
调用的时候,必须传入参数名:
>>> person('小明',20,job='工程师',city='北京','签名:小红我爱你啊')
SyntaxError: positional argument follows keyword argument
>>> person('小明',20,job='工程师',city='北京')
小明 20 工程师 北京
>>> person('小明',20,'工程师','北京')
Traceback (most recent call last):
File "<pyshell#70>", line 1, in <module>
person('小明',20,'工程师','北京')
TypeError: person() takes 2 positional arguments but 4 were given
参数组合
在定义函数的时候,可以用必选参数、默认参数、可变参数、关键字参数和命名参数或者它们的组合。但是参数定义的顺序必须是:必选参数、默认参数、可变参数、命名关键字参数和关键字参数。
def f1(a, b, c=0, *args, **kw):
print('a =', a, 'b =', b, 'c =', c, 'args =', args, 'kw =', kw)
def f2(a, b, c=0, *, d, **kw):
print('a =', a, 'b =', b, 'c =', c, 'd =', d, 'kw =', kw)
在调用的时候:
>>> f1(1, 2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1, 2, c=3)
a = 1 b = 2 c = 3 args = () kw = {}
>>> f1(1, 2, 3, 'a', 'b')
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {}
>>> f1(1, 2, 3, 'a', 'b', x=99)
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
还可以使用 tuple 和 dict 调用。任意函数,都可以通过类似 func(args,*kw)的形式调用它,无论参数是怎么定义的:
>>> args = (1, 2, 3, 4)
>>> kw = {'d': 99, 'x': '#'}
>>> f1(*args, *kw)
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
>>> args = (1, 2, 3)
>>> kw = {'d': 88, 'x': '#'}
>>> f2(args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}