位置参数
我们在利用函数计算一个数的平方时,必须要给这个函数传入一个参数——即我们要计算平方的数。
def pow(x):
return x * x
对于函数pow来说,x就是一个位置参数,当调用这个函数时,x是必须传入有且唯一的一个参数。
当我们想计算 x3,可以定义另一个函数,那求x4呢,还要再定义吗,其实我们只需对pow
函数稍加改动即可
def pow(x, n):
prod = 1
while n > 0:
prod = prod * x
n = n-1
return prod
这时,x 和 n 就都是位置参数,在调用时必须同时传入,按照顺序依次赋值给x 和 n。
默认参数
在实际应用中我们必须考虑这种情况:一般求幂都是求平方,每次使用pow
函数都要输入两个参数未免太麻烦了些,所以有了默认参数,即这个参数有个缺省值,在不输入是默认为缺省值。
【例1】:
def pow(x, n = 2):
prod = 1
while n > 0:
prod = prod * x
n = n-1
return prod
当把n由变成n=2时,位置参数就变成了默认参数,当我们只传入一个参数时,n默认为2。即pow(3)
计算的是32。
对于其他n>2
的情况,就必须要传入两个参数了。
使用默认参数有以下情况需要注意:
函数的参数可以全由默认参数组成
但当位置参数和默认参数同时存在时,默认参数必须定义在位置参数的后面,否则会报错
如何设置默认参数:
一般把变化大的设为位置参数,变化小的(默认值使用次数占多)设为默认参数,如【例1】 的pow
函数
当有多个默认参数时,可以不按照默认参数的定义顺序给出,但必须同时给出参数名称,如【例2】:
【例2】:
def enroll(name, gender, age = 6, city = 'Beijing', district = 'Chaoyang'):
print('name:', name)
print('gender:', gender)
print('age:', age)
print('city:', city)
print('district:', district)
我们可以这样调用:enroll('xiaoming', 'M', district = 'Jizhou', city = 'Tianjin')
运行结果:
name: xiaoming
gender: M
age: 6
city: Tianjin
district: Jizhou
重点:默认参数必须指向不变对象
【例3】:
def add_end(L = []):
L.append('end')
return L
当我们第一次运行该函数时,结果正常:
>>> add_end()
['end']
但当我们再运行时,会发现:
>>> add_end()
['end', 'end']
>>> add_end()
['end', 'end', 'end']
每次运行都会记录这个添加的end
结尾,但这并非我们的本意,究竟为何如此呢?
我们定义的默认参数L
是个变量,其指向为 [] 这个list,但运行一次之后,其指向的list内容发生了改变,已经变成['end'],默认参数的内容就变了,不再是函数定义时的 [] 了。
所以:
定义默认参数要牢记一点:默认参数必须指向不变对象!
有哪些数据类型是不变对象呢,比如:str,None
,不变对象一旦创建,其内部数据便不可更改,减少了由于修改数据导致的错误。
可变参数
可变参数,顾名思义,就是传入参数的数量可以变化,可以是1个,2个,3个……
【例4】:
def cal(numbers):
sum = 0
for x in numbers:
sum = sum + x
return sum
由此我们可以计算1+2+4+5+8+...的值了,但每次调用我们传入的numbers参数必须是一个 list 或 tuple,较麻烦。此时的numbers是一个位置参数,不是可变参数。
稍加改动,即可将 numbers 定义为一个可变参数
【例4.1】
def cal(*numbers):
sum = 0
for x in numbers:
sum = sum + x
return sum
只是在numbers前加了个*
,numbers就成为了可变参数,我们在调用此函数时可以这样调用:
cal(1,2,3,6,7,8)
,此时numbers接收到的是一个tuple,函数代码不变,函数即可传入任意个参数,包括0个参数。
>>> cal(3,56,7,8)
74
>>> cal()
0
如果numbers是位置参数时则0个参数会报错,因为位置参数是必须传入的。
当我已经有一个 list 或 tuple 了怎么把它传入函数中,可以这样做:
>>> num = [1,3,5,6,7,8]
>>> cal(*num)
30
在 list 或 tuple 前加一个*就能将其传入函数中了。
关键字参数
可变参数是可以传入任意个(包括0个)参数,这些可变参数在传入时会自动组装成一个tuple。关键字参数是允许你传入任意个(包括0个)含参数名的参数,这些关键字参数会自动组装成为一个dict
【例5】:
def person(name, age, **kw):
print('name:', name, 'age:', age, kw)
函数person
在调用时除了接受必选参数name
和age
,还接受关键字参数kw
。调用时可以只传入位置参数
>>> person('xiaoming','6')
name: xiaoming age: 6 {}
也可以传入任意个数的关键字参数:
>>> person('xiaoming','6',city = 'Beijing', job = 'Engineer')
name: xiaoming age: 6 {'city': 'Beijing', 'job': 'Engineer'}
可以看到,两个关键字参数已经自动组成为dict了。
应用场景:
在用户注册时,用户可以只填入姓名,年龄两个参数,但提供城市,职业等参数选填。
与可变参数相同,我们也可以提前组装好一个dict,之后利用**dict名
将其传入函数:
>>> d = { 'city' : 'Beijing', 'job' : 'Engineer'}
>>> person('xiaoming', 6, **d)
name: xiaoming age: 6 {'city': 'Beijing', 'job': 'Engineer'}
**d
会将此dict的所有key-value用关键字参数传入到函数的**kw
参数中,kw
将获得一个dict,其获得的是d
的一份拷贝,对**kw做任何改动不会影响d
。
命名关键字参数
关键字参数允许我们传入任意个含参数名的关键字参数,但是考虑到限制用户输入的随意性,如何让用户只传入规定的关键字参数呢。比如,只接受city
和job
作为关键字参数,可以这样定义:
def person(name, age, *, city, job):
print(name, age, city, job)
和关键字参数**kw
不同,命名关键字参数只需要一个特殊分隔符*
,*
后面的参数都会被视为命名关键字参数。
调用方式如下:
>>> person('xiaoming',6,city = 'Beijing', job = 'Engineer')
xiaoming 6 Beijing Engineer
命名关键字参数调用时必须写参数名,不写的话函数会默认将其视为位置参数,将会报错。
如果命名关键字参数前面有可变参数,则省略*
作为分隔符,可变参数后的参数自动视为命名关键字参数,不必担心混淆,命名关键字参数传入时必须包含参数名。
def person(name, age, *args , city, job):
print(name, age,args, city, job)
>>> person('xiaoming',6, 'This is a smart boy', 'allergic to egg', city = 'Beijing', job = 'Engineer')
xiaoming 6 ('This is a smart boy', 'allergic to egg') Beijing Engineer
命名关键字参数也可以有缺省值,从而简化调用:
def person(name, age, *args , city = ‘Beijing, job):
print(name, age,args, city, job)
>>> person('xiaoming',6, 'This is a smart boy', 'allergic to egg', job = 'Engineer')
xiaoming 6 ('This is a smart boy', 'allergic to egg') Beijing Engineer
注意:
使用命名关键字参数时,如果前面没有可变参数,必须加特殊分隔符*
。如果不加,python将无法识别位置参数和命名关键字参数。
参数组合
这五种参数可以组合使用,但参数定义的顺序必须是:
位置参数-->默认参数-->可变参数-->命名关键字参数-->关键字参数
注意命名关键字参数和关键字参数的顺序。
比如定义一个函数,包含若干上述参数:
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包含位置参数,默认参数,可变参数,关键字参数。
f2包含位置参数,默认参数,命名关键字参数,关键字参数。
其中可变参数在传入时自动组成一个tuple,关键字参数传入时自动组成一个dict。
函数调用时,python解释器会自动按参数位置和参数名把对应的参数传进去。
f1可以只传入位置参数,f2必须传入的有位置参数,命名关键字参数。
>>> f1(1,2)
a = 1 b = 2 c = 0 args = () kw = {}
>>> f1(1,2,4)
a = 1 b = 2 c = 4 args = () kw = {}
>>> f1(1,2,c=4)
a = 1 b = 2 c = 4 args = () kw = {}
>>> f1(1,2,4,'ab',2)
a = 1 b = 2 c = 4 args = ('ab', 2) kw = {}
>>> f1(1,2,4,'ab',2,city = 'Beijing')
a = 1 b = 2 c = 4 args = ('ab', 2) kw = {'city': 'Beijing'}
>>> f2(1,2,4,d = 6)
a = 1 b = 2 c = 4 d = 6 kw = {}
>>> f2(1,2,4,d = 6,city = 'Beijing')
a = 1 b = 2 c = 4 d = 6 kw = {'city': 'Beijing'}
>>> f2(1, 2, d=99, ext=None)
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
最神奇的是,通过一个tuple和dict,你也可以调用上述函数:
>>> 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':456,'city':'Beijing'}
>>> f2(*args,**kw)
a = 1 b = 2 c = 3 d = 456 kw = {'city': 'Beijing'}
无论函数是如何定义的,都可以通过类似func(*args,**kw)
的方式调用它。
最后:
不要同时使用太多的组合,会使函数接口的可理解性很差