前记
定义函数时,把参数的名字和位置确定,函数的接口定义就完成。函数调用者只需要知道如何传递正确的参数,以及函数返回什么值,函数内部的逻辑被封装;
python函数定义中,除了正常定义的必选参数外,还有默认参数、可变参数、关键字参数。
默认参数一定要用不可变对象。
可变参数和关键字参数:
*args:可变参数,args接收一个tuple;
**kw:关键字参数,kw接收一个dict;
可变参数可直接传入,如func(1,2,3),又可组装list或tuple,再通过*args传入,如func(*(1,2,3));
关键字参数可直接传入,如func(a=1,b=2),又可组装dict,再通过**kw传入,如func(**{'1':a,'2':b});
命名关键字参数,可限制调用者传入的参数名,同时可提供默认值。
定义命名的关键字参数在没有可变参数条件下,一定要使用分隔符*,否则定义的是位置参数。
一、位置参数
示例:
def power(x):
return x*xprint(power(5))
power(x)函数中,x就是位置参数。调用power(x)时,必须传入有且仅有一个参数x。示例:
def power(x,n):
s = 1
while n > 0:
n = n - 1
s = s * x
return sprint(power(5,2))
power(x,n)计算任意n次方,有两个位置参数,调用函数时,传入的两个值按照位置顺序依次赋给x和n。
二、默认参数
示例:
def power(x,n = 2):
s = 1
while n > 0:
n = n - 1
s = s * x
return sprint(power(5))
print(power(5,2))
第二个参数n默认为2,默认参数可简化函数的调用。
设置默认参数时,注意:
1、必选参数在前,默认参数在后。
2、当函数有多个参数时,变化大的参数方前面,变化小的参数放后面。变化小的作为默认参数。
3、当不按顺序提供默认参数时,需要把参数名写上。默认参数的坑:
def add_end(L=[]):
L.append('END')
return Lprint(add_end())
print(add_end())
输出:
['END']
['END', 'END']原因:python函数定义时,默认参数L的值就被计算出来了,即[],默认参数是一个变量,指向对象[],每次调用函数,如果改变L的内容,则下次调用时,默认参数的内容就变了,不再是定义的[].
牢记:默认参数必须指向不变对象。test:
def add_end(L=[]):
print("L init is",L)
L.append('END')
return Lprint(add_end())
print(add_end())
输出:
L init is []
['END']
L init is ['END']
['END', 'END']修改上面示例,用None不变对象实现:
def add_end(L=None):
if L == None:
L = []
L.append('END')
return Lprint(add_end())
print(add_end())
输出:
['END']
['END']注:不变对象一旦创建,对象内部的数据不能修改。
三、可变参数
即传入的参数个数是可变的。
示例:
def calc(numbers):
sum = 0
for n in numbers:
sum = sum + n
return sumprint(calc([1,2,3,4]))
print(calc((1,2,3,4)))
输出:
10
10
结论:把参数作为list或tuple传入;
利用可变参数,如下示例:
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n
return sumprint(calc(1,2,3,4))
输出:
10
结论:定义可变参数和定义一个list或tuple参数相比,仅仅在参数前面加一个*号。在函数内部,参数接收到的是一个tuple。如果有一个list或tuple,调用可变参数:
nums=[1,2,3]
print(calc(*nums))
*nums表示把nums这个list的所有元素作为可变参数传进去。
四、关键字参数
可变参数允许传入任意个参数,可变参数在函数调用时自动组装为一个tuple。
关键字参数允许传入任意个含参数名的参数。这些关键字参数在函数内部自动组装为一个dict。
示例:
def person(name,age,**kw):
print("name=",name,"age=",age,"kw=",kw)person("Michael",24)
person("Tom",30,city="beijing",job="Engineer")
extra = {"city":"shanghai","job": "Engineer"}
person("Jack",28,**extra)
输出:
name= Michael age= 24 kw= {}
name= Tom age= 30 kw= {'city': 'beijing', 'job': 'Engineer'}
name= Jack age= 28 kw= {'city': 'shanghai', 'job': 'Engineer'}
结论:**extra表示把extra这个dict的所有ke-value用关键字参数传入函数的**kw参数,kw获得一个dict,即kw获得extra的一份拷贝,对kw的修改不影响extra。
五、命名关键字参数
对于关键字参数,调用者可传入任意不受限制的关键字参数。
如果限制关键字参数的名字,可以用命名关键字参数。
示例:
def person(name,age,*,city,job):
print(name,age,city,job)person("Jack",28,city="beijing",job="Engineer")
输出:
Jack 28 beijing Engineer结论:和关键字**kw不同,命名关键字参数使用*隔开,*后面的参数视为命名关键字参数。
示例:
def person(name,age,*args,city,job):
print(name,age,args,city,job)person("Jack",28,city="beijing",job="Engineer")
#person("Jack",28,"beijing","Engineer")
#上面语句报错:SyntaxError: invalid character in identifier
输出:
Jack 28 () beijing Engineer
六、参数组合
定义函数,可将必选参数、默认参数、可变参数、关键字参数、命名关键字参数,5种组合使用;
注意:参数顺序必须是:必选参数、默认参数、可变参数、关键字参数、命名关键字参数。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, 3, 'a', 'b', x=99)
f2(1, 2, d=99, ext=None)args = (1, 2, 3, 4)
kw = {'d': 99, 'x': '#'}
f1(*args, **kw)args = (1, 2, 3)
kw = {'d': 88, 'x': '#'}
f2(*args, **kw)
输出:
a = 1 b = 2 c = 3 args = ('a', 'b') kw = {'x': 99}
a = 1 b = 2 c = 0 d = 99 kw = {'ext': None}
a = 1 b = 2 c = 3 args = (4,) kw = {'d': 99, 'x': '#'}
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}
结论:
1、python自动按照参数位置和参数名把对应参数传入;
2、任意函数,都可通过func(*args,**kw)形式调用;
3、不要同时使用太多组合,会导致函数借口可理解性差。
注:如有错误,请指正。