1.函数参数定义的顺序:必选参数(位置参数)、默认参数、可变参数、关键字参数、命名关键字参数
2.默认参数
(1)即,传的参数里面有默认值,可以通过传参替换;
(2)当有多个默认参数时,调用的时候,既可以按顺序提供,比如函数原定义enroll(name,sex,age=18,city="Beijing"),调用时可以enroll('Bob', 'M', 7),意思是,除了name,sex这两个参数外,最后1个参数应用在参数age上,city参数由于没有提供,仍然使用默认值;也可以不按顺序提供部分默认参数,但需要把参数名写上。如调用enroll('Adam', 'M', city='Tianjin'),意思是,city参数用传进去的值,其他默认参数继续使用默认值;
(3)但是会出现一个坑,如下:
def f(L=[]):
L.append("aaa")
return L
#正常调用,正常
print(f([1, 2, 3])) # [1, 2, 3, 'aaa']
#开始使用默认参数,首次正常
print(f()) # ['aaa']
#再次调用,使用默认参数,就存在问题了
print(f()) # ['aaa', 'aaa']
print(f()) # ['aaa', 'aaa', 'aaa']
#原因解释如下:
#Python函数在定义的时候,默认参数L的值就被计算出来了,即[],因为默认参数L也是一个变量,它指向对象[],每次调用该函数,如果改变了L的内容,则下次调用时,默认参数的内容就变了,不再是函数定义时的[]了。
print(f([4, 5])) # [4, 5, 'aaa']
上述现象可以如下更改:
def f(L=None):
if L is None:
L = []
L.append("aaa")
return L
print(f([1, 2, 3])) # [1, 2, 3, 'aaa']
print(f()) # ['aaa']
print(f()) # ['aaa']
print(f()) # ['aaa']
print(f([4, 5])) # [4, 5, 'aaa']
因此,定义默认参数必须指向不变对象;
为啥呢?因为不变对象一旦创建,其内部的数据就不能修改,这样就减少了由于修改数据而导致的错误;此外,由于对象不变,多任务环境下同时读取对象不需要加锁,同时读就不会有问题;
3.可变参数
(1)即,就是传入的参数个数是可变的,可以是0个、1个、2个到任意个;
(2)以计算传入参数之和为例:
def calc(numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
#调用的时候,需以list或tuple形式传入
print(calc([1, 2, 3])) #14
print(calc((1, 2, 3))) #14
(3)再把传入的参数改为可变参数:
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
#在函数内部,参数numbers接收到的是一个tuple,但调用该函数时,可以传入任意个参数,包括0个参数
print(calc(1, 2, 3)) #14
print(calc()) #0
(4)基于以上,如果可变参数本身是一个list或tuple
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
#可以在list或tuple前面加一个*号,把list或tuple的元素变成可变参数传进去:
nums = [1, 2, 3]
print(calc(*nums)) # 14
注:*nums获得的是nums的一份拷贝,对*nums的改变不会影响nums的值
nums = [1, 2, 3]
print(calc(*nums, 4)) # 30
print("nums : ")
print(nums)
4.关键字参数
(1)允许你传入0个或任意个含参数名的参数,这些关键字参数在函数内部自动组装为一个dict;
def person(name, age, **kw):
print("Name:", name, " Age:", age, "Other:", kw)
person("Mike", 22) # Name: Mike Age: 22 Other: {}
person("Mike", 22, sex="male") # Name: Mike Age: 22 Other: {'sex': 'male'}
person("Mike", 22, sex="male", city="Beijing") # Name: Mike Age: 22 Other: {'sex': 'male', 'city': 'Beijing'}
extra = {"sex": "male", "city": "Beijing",
"job": {"job1": "Doctor", "job2": "Teacher"}}
person("Mike", 22, sex=extra["sex"], city=extra["city"], job=extra["job"]) #Name: Mike Age: 22 Other: {'sex': 'male', 'city': 'Beijing', 'job': {'job1': 'Doctor', 'job2': 'Teacher'}}
person("Mike", 22, **extra, love="sing") #Name: Mike Age: 22 Other: {'sex': 'male', 'city': 'Beijing', 'job': {'job1': 'Doctor', 'job2': 'Teacher'}, 'love': 'sing'}
(2)**extra表示把extra这个dict的所有key-value用关键字参数传入到函数的**kw参数,kw将获得一个dict
(3)注:kw获得的dict是extra的一份拷贝,对kw的改动不会影响到函数外的extra,如下:
def person(name, age, **kw):
kw["extrahaha"] = "lalala"
print("Name:", name, " Age:", age, "Other:", kw)
person("Mike", 22, **extra, love="sing") #Name: Mike Age: 22 Other: {'sex': 'male', 'city': 'Beijing', 'job': {'job1': 'Doctor', 'job2': 'Teacher'}, 'love': 'sing', 'extrahaha': 'lalala'}
print("extra : ")
print(extra) #{'sex': 'male', 'city': 'Beijing', 'job': {'job1': 'Doctor', 'job2': 'Teacher'}}
info = {"age": 18, "name": "Ann", "sex": "female", "city": "Shanghai"}
person(**info) # Name: Ann Age: 18 Other: {'sex': 'female', 'city': 'Shanghai', 'extrahaha': 'lalala'}
5.命名关键字参数
(1)如果要限制关键字参数的名字,就可以用命名关键字参数。命名关键字参数需要一个特殊分隔符 * ,*后面的参数被视为命名关键字参数
def student(name, age, *, city, sex):
print(name, age, city, sex)
student("Anna", 15, city="Beijing", sex="female") # Anna 15 Beijing female
info = {"age": 18, "name": "Ann", "sex": "female", "city": "Shanghai"}
student(**info) # Ann 18 Shanghai female
(2)如果函数定义中已经有了一个可变参数,后面跟着的命名关键字参数就不再需要一个特殊分隔符*了
def student(name, age, *args, city, sex):
print(name, age, args, city, sex)
ex = [1, 2, 3]
student("Anna", 15, *ex, city="Suzhou", sex="male") #Anna 15 (1, 2, 3) Suzhou male
(3)命名关键字参数可以有缺省值:
def student(name, age, *, city="Hangzhou", sex):
print(name, age, city, sex)
student("Anna", 15, sex="male") # Anna 15 Hangzhou male
(4)使用命名关键字参数时,要特别注意,如果没有可变参数,就必须加一个*作为特殊分隔符。如果缺少*,Python解释器将无法识别位置参数和命名关键字参数
def student(name, age, *, city="Hangzhou", sex):
print(name, age, city, sex)
# student("Anna", 15, "Beijing", "female") # 报错TypeError: student() takes 2 positional arguments but 4 were given
6.组合参数
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}
args = (1, 2, 3, 4, 5, 6)
kw = {"d": 99, "x": "###"}
f1(*args, **kw) # a= 1 b= 2 c= 3 args= (4,5,6) kw= {'d': 99, 'x': '###'}
args = (1, 2, 3,)
kw = {"d": 919, "x": "###"}
f2(*args, **kw) # a= 1 b= 2 c= 3 d= 919 kw= {'x': '###'}
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": 919, "x": "###"}
f2(*args, **kw) # a= 1 b= 2 c= 3 d= 919 kw= {'x': '###'}
在函数调用的时候,Python解释器自动按照参数位置和参数名把对应的参数传进去