目录
Python函数的参数非常灵活:
- 形参(函数定义时):普通参数(位置参数)、默认参数、可变参数(可变位置参数,可变关键字参数)、命名关键字参数;
- 实参(调用函数时):位置参数,关键字参数;
不同类型的参数,定义时顺序很重要(必须按以下顺序给出不同类型参数):
def func(positional_args, keyword_args, *tuple_grp_args, **dict_kw_args):
# ...
可变参数
可变位置参数
定义参数时前面加一个星号*
,表示这个参数是可变的,可以接受任意多个参数,这些参数构成一个元组(只能通过位置参数传递)。
传递参数时,可迭代对象(元组、列表)可通过在前面加一个星号*
,解构成位置参数(依次把元素传递给函数)。
def calcSum(*numbers):
sum = 0
for n in numbers:
sum += n
return sum
print(calcSum())
print(calcSum(1,2,3))
print(calcSum(*(1,2,3)))
print(calcSum(*[1,2,3]))
可变关键字参数
定义参数时前面加两个星号**
,表示这个参数为可变关键字参数,可以接受任意多个参数,这些参数构成一个字典,只能通过关键字参数传递。
传递参数时,字典对象(Key必须为str类型)可通过在前面加两个星号**
,解构为关键字参数。
def add(a,b):
return a+b
data = {'a':3,'b':4}
print(add(**data)) #关键字参数解构
混合使用
当可变位置参数和可变关键字参数一起使用时候,可变位置参数必须在前。
def fn(x,y,*args,**kwargs):
print(x) # 1
print(y) # 2
print(args) # (3,4,5)
print(kwargs) # {'a':6, 'b':7}
fn(1,2,3,4,5,a=6,b=7)
强制关键字参数
关键字参数能够使函数调用意图更加明确;对于容易混淆参数的函数,可以声明只能以关键字形式给出的参数(特殊参数*
以后的参数,都是强制关键字参数)。
# key与value参数只能以关键字参数方式给出
def keyParam(one, *, key, value='v'):
print(one, key, value)
if __name__=="__main__":
keyParam(1, key='one')
keyParam(1, key='one', value='one-1')
默认参数
参数的默认值,会在每个模块加载时(很多模块会在程序启动时加载)求出;模块一旦加载,参数的默认值就固定不变了;而且所有使用默认参数的函数都共享此默认值,若默认值为动态值(如字典、列表等),会产生奇怪的行为(任何一个函数对其的修改,都会影响其他函数)。
def logMsg(msg:str, when=datetime.datetime.now()):
print(when, msg)
def logMsg2(msg:str, when=None):
when = when if when else datetime.datetime.now()
print(when, msg)
if __name__=="__main__":
logMsg('one-befor')
logMsg2('two-befor')
print('wait one second')
time.sleep(1)
logMsg('one-after')
logMsg2('two-after')
# one-befor与one-after的时间是相同的,都是模块加载时的时间
注意:若参数默认类型是可变类型,一定用None作为默认值,然后在代码中设定所需的默认值。如下所示,getCode调用会不断累加默认值(作为默认值的列表,会不断的追加内容):
def getCode(msg:str, code:list=[]):
code.append(msg)
print(code)
def getCode2(msg:str, code:list=None):
if code is None:
code = []
code.append(msg)
print(code
if __name__=="__main__":
getCode('one') # ['one']
getCode2('one') # ['one']
getCode('two') # ['one', 'two']
getCode2('two') # ['two']