位置参数
调用函数时根据函数定义的参数位置来传递参数。
编写x的n次方的函数
def power(x, n):
s = 1
while n > 0:
s = s * x
n = n - 1
return s
x,n为位置函数,两个参数的顺序必须一一对应,且少一个参数都不行。
默认参数
为避免代码少一个参数而无法正常调用,故使用默认参数。
还是编写x的n次方的函数
def power(x, n=2):
s = 1
while n > 0:
s = s * x
n = n - 1
return s
当调用power(9)时,相当用调用power(9, 2)
>>> def power(x, n=2):
s = 1
while n > 0:
s = s * x
n = n - 1
return s
>>> power(9)
81
从上面的例子可以看出,默认参数可以简化函数的调用。设置默认参数时,有几点要注意:
1. 必选参数在前,默认参数在后,否则Python的解释器会报错;
2. 是如何设置默认参数
当函数有多个参数时,把变化大的参数放前面,变化小的参数放后面。变化小的参数就可以作为默认参数。
默认参数易错点:
定义一个函数
>>> def add_end(L = []):
L.append('end')
return L
>>> add_end([1,2,3])
[1, 2, 3, 'end']
若使用默认参数时,出现以下结果
>>> add_end()
['end']
>>> add_end()
['end', 'end']
>>> add_end()
['end', 'end', 'end']
第一次使用默认参数L = [],结果为L = ['end'],在第二次调用默认参数时,L变量发生了变化,默认参数随着发生变化,不再是最初定义的[]。
由此可得:默认参数必须指向不变对象!
为避免以上情况,可使用None这个不变对象
>>> def add_end(L = None):
if L is None:
L = []
L.append('end')
return L
>>> add_end()
['end']
>>> add_end()
['end']
>>> add_end()
['end']
为什么要设计str、None这样的不变对象?
因为不变对象一旦创建,对象内部的数据就不能修改,这样就减少了由于修改数据导致的错误。此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读一点问题都没有。我们在编写程序时,如果可以设计一个不变对象,那就尽量设计成不变对象。
可变参数意思是传入的参数个数是可变的。
>>> def calc(*num):
sum = 0
for i in num:
sum = sum + i * i
return sum
>>> calc(1,2,3)
14
>>> calc(2,3,5,6)
74
>>> calc()
0
可变参数是在参数前添加一个*号,在使用该函数时,在函数内部,参数num接收到的是一个tuple,而针对使用可变参数*num,可以传入任意个参数,包括0个参数。
同理,在list或tuple前加一个*号,即可将list或tuple元素变为可变参数传入函数中。
关键字参数
可变参数允许你传入0个或任意个参数,这些可变参数在函数调用时自动组装为一个tuple。而关键字参数允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict,例如:
>>> def person(name, age, **kw):
print('name: ', name, 'age: ', age, 'other: ', kw)
>>> person('Nelson', 27, 'Xi\'an')
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
person('Nelson', 27, 'Xi\'an')
TypeError: person() takes 2 positional arguments but 3 were given
关键字参数必须传入参数名。
>>> person('Nelson', 27, city = 'Xi\'an')
name: Nelson age: 27 other: {'city': "Xi'an"}
关键字参数可以扩展函数的功能,如以上person函数中,可以保证接收到name,age两个参数,但是如果调用者愿意提供更多的信息,同样可以收到。
与可变参数类似,可将一个dict转换为关键字参数传进函数中,
>>> extra = {'city': 'Xi\'an', 'sex': 'male'}
>>> extra
{'city': "Xi'an", 'sex': 'male'}
>>> person('Nelson', 27, city = extra['city'], sex = extra['sex'])
name: Nelson age: 27 other: {'city': "Xi'an", 'sex': 'male'}
>>> person('Nelson', 27, **extra)
name: Nelson age: 27 other: {'city': "Xi'an", 'sex': 'male'}
1. 将dict中的key对应的value传入关键字参数中;
2. (简化)**extra表示把extra这个dict中的所用key-value用关键字参数传入到函数的**kw参数中,kw获得了一个dict。注意:kw获得的dict只是对extra的一份拷贝,改动kw不会影响extra。
命令关键字参数
关键字参数可令函数的调用者传入任意不受限制的关键字参数,而命令关键字参数可以限制关键字参数的名字,例如:
>>> def person(name, age, *, city, sex):
print(name, age, city, sex)
>>> person('Nelson', 27, city = 'Xi\'an', sex = 'male')
Nelson 27 Xi'an male
与关键字参数**kw不同,命名关键字参数需要一个特殊分隔符*,*后面的参数被视为命令关键字参数。
如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了,例如:
>>> def person(name, age, *args, city, sex):
print(name, age, args, city, sex)
>>> person('Nelson', 27, 'Xi\'an', 'male')
Traceback (most recent call last):
File "<pyshell#4>", line 1, in <module>
person('Nelson', 27, 'Xi\'an', 'male')
TypeError: person() missing 2 required keyword-only arguments: 'city' and 'sex'
>>> person('Nelson', 27, city = 'Xi\'an', sex = 'male')
Nelson 27 () Xi'an male
>>> person('Nelson', 27, 'handsome', city = 'Xi\'an', sex = 'male')
Nelson 27 ('handsome',) Xi'an male
命令关键字参数必须传入参数名,若没有传入参数名,调用就会报错TypeError。
另外,命令关键字参数可以设置缺省值,调用时,可不传入设置了缺省值的参数,例如:
>>> def person(name, age, *args, city = 'Beijing', sex = 'female'):
print(name, age, args, city, sex)
>>> person('Bob', 12)
Bob 12 () Beijing female
>>> person('Bob', 16, city = 'Shenzhen')
Bob 16 () Shenzhen female
参数组合在Python中定义函数,可以用位置参数、默认参数、可变参数、关键字参数和命名关键字参数,这5种参数都可以组合使用。
请注意,这五种参数定义的顺序为:位置参数、默认参数、可变参数、命令关键字参数、关键字参数,例如:
>>> def f1(a, b, c = 1, *, d, **kw):
print('a', a, 'b', b, 'c', c, 'd', d, 'kw', kw)
>>> f1(1,2)
Traceback (most recent call last):
File "<pyshell#16>", line 1, in <module>
f1(1,2)
TypeError: f1() missing 1 required keyword-only argument: 'd'
>>> f1(1, 2, d = 'hello', x = 'world', z = '!')
a 1 b 2 c 1 d hello kw {'x': 'world', 'z': '!'}
以上代码中,命令关键字参数d未传入数据,产生TypeError错误。
同时可以使用一个tuple以及一个dict调用以上函数f1(),例如:
>>> def f1(a, b, c = 1, *, d, **kw):
print('a=', a, 'b=', b, 'c=', c, 'd=', d, 'kw=', kw)
>>> f1(1, 2, d = 'hello', x = 'world', z = '!')
a= 1 b= 2 c= 1 d= hello kw= {'x': 'world', 'z': '!'}
>>> args = (1,2,3,4)
>>> kw = {'d':21, 'x':'hello'}
>>> f1(*args, **kw)
Traceback (most recent call last):
File "<pyshell#23>", line 1, in <module>
f1(*args, **kw)
TypeError: f1() takes from 2 to 3 positional arguments but 4 positional arguments (and 1 keyword-only argument) were given
>>> args = (1,2,3)
>>> kw = {'d':21, 'x':'hello'}
>>> f1(*args, **kw)
a= 1 b= 2 c= 3 d= 21 kw= {'x': 'hello'}
以上代码中,第一次运行产生错误原因为:传入可变参数与函数定义参数数量不同,发生错误。
故,对于任意函数,都可以利用类似func(*args, **kw)形式调用它。