函數的參數
轉瞬一年,又快到動物們交...(*/?\*),嘛~拖更無限好...
咳咳,去年說的函數的定義時有包含參數,只要把參數的名字和位置確定下來,函數的 接口 定義就完成了。函數調用者只需知道如何傳遞正確的參數,以及函數將返回什么樣的值就夠了,內部的復雜邏輯被封裝,無需了解。
位置參數
def power(x):
return x * x
對于上述的 power(x) 函數,參數 x 就是一個位置參數。位置參數可以有多個。例如將上述程序做如下修改,調用的時候,傳入兩個值按照位置順序依次賦予 x 和 n :
def power(x, n):
s = 1
while n > 0:
n = n - 1
s = s * x
return s
默認參數
重新定義的 power(x,n) 可以用在計算任意 n 次方,但是舊的代碼調用失效了,如果只是輸入一個參數,會使得舊代碼因缺少一個參數而無法正常調用:
>>> power(5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: power() missing 1 required positional argument: 'n'
如果想要舊代碼那種,輸入一個參數,自動獲得平方結果。就可以使用默認參數了:
def power(x,n=2):
s= 1
while n > 0:
n = n-1
s = s * x
return s
之后,運行:
>>>power(5)
>>>25
設置默認參數需要注意幾點:
一、必選參數在前,默認參數在后,否則 Python 解釋器會報錯;
二、函數變化大的參數放前面,小的就可以作為默認參數放在后頭;
設置默認參數可以降低函數的難度,復雜點的函數也可以放多幾個參數,也方便用戶使用。eg:
def enroll(name,gender,age=6,city='beijing'):
print('name:',name)
print('gender:',gender)
print('age:',age)
print('city:',city)
運行:
>>> enroll('Lily','F')
name: Lily
gender: F
age: 6
city: beijing
不按照順序給參數:
>>> enroll('Lala','C','city=shanwei')
但是默認參數使用不當,也會出現不少bug,例如:
def add_end(L=[]):
L.append('END')
return L
此程序在正常調用時是傳入一個 list,在其末尾處放入個 END,再返回,例如[1,2,3],返回[1,2,3,'END']。但是如果使用默認參數調用時,第一次正常,但是多調用幾次就可以發現...
原因很簡單,默認參數指向了可變對象,所以 L 好像記住了 'END'。所以定義默認參數還需要注意,默認參數必須指向不可變對象(str/None等)!
修改法:
def add_end(L=None):
if L is None:
L=[]
L.append('END')
return L
可變參數
可變參數,參數的數量可以任意個。以數學題為例,給定一組數字a,b,c...,要求計算出它們的平方和。方法之一可以將這組數字作為 list 或者 tuple 參數傳入:
def calc(numbers):
sum = 0
for n in numbers:
sum=sum+nn
return sum
但是每次得先把這組數據組成 list 或者 tuple,例如calc([1,2,3])是略微麻煩的。可以稍微改動一下:
def calc(numbers):
sum = 0
for n in numbers:
sum=sum+n*n
return sum
代碼基本不變,但是加了個 ,就可以直接傳入所需要的數據參數了,calc(1,2,3)。
而如果已經有了一個 list 或 tuple 數據參數,例如nums=[1,2,3],導入可不需要 calc(nums[0],nums[1],nums[2]),只需要在調用時輸入 calc(*nums) 即可。
nums 表示把 nums 這個 list 的所有元素作為可變參數傳進去。
關鍵字參數
可變參數允許傳入任意個參數,這些參數在函數調用時自動組裝成一個 tuple 。而關鍵字參數是允許傳入任意個參數,然后在調用函數的時候自動組裝成一個 dict。
eg:
def person(name,age,**kw):
print('name:',name,'age:',age,'other:',kw)
調用:
>>> person('小明',20)
name: 小明 age: 20 other: {}
>>> person('小紅','18',性別='男',QQ簽名='小明滾犢子,我們不會在一起的')
name: 小紅 age: 18 other: {'性別': '男', 'QQ簽名': '小明滾犢子,我們不會在一起的'}
關鍵字參數可以用在例如用戶注冊的場景,需要輸入的位置參數是必填選項,關鍵字參數是可選,例如備注等。
當然跟可變參數一樣,可以先組裝個 dict ,然后再導入:
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, city=extra['city'], job=extra['job'])
也可以用可變參數類似的方法 **extra,把extra這個dict的所有key-value用關鍵字參數傳入到函數的**kw參數,kw將獲得一個dict,注意kw獲得的dict是extra的一份拷貝,對kw的改動不會影響到函數外的extra。
命名關鍵字
函數的調用者可以傳入任意不受限制的關鍵字參數,但至于傳入了哪些就需要在函數內部通過 kw 檢查。
def person(name, age, **kw):
if 'city' in kw:
# 有city參數
pass
if 'job' in kw:
# 有job參數
pass
print('name:', name, 'age:', age, 'other:', kw)
但是如果要限制關鍵字參數的名字,就可以命名關鍵字。例如只接收 city 和 job 作為關鍵字參數,可以由缺省值,簡化調用:
def person(name,age,*,job='teacher',city):
print(name,age,job,city)
如果定義中已經有一個可變參數,后面跟著的命名關鍵字就不再需要一個特殊分隔符 * ,但是沒有可變參數的時候必須有分隔符 * :
def person(name,age,*args,job,city):
print(name,age,args,job,city)
調用的時候,必須傳入參數名:
>>> person('小明',20,job='工程師',city='北京','簽名:小紅我愛你啊')
SyntaxError: positional argument follows keyword argument
>>> person('小明',20,job='工程師',city='北京')
小明 20 工程師 北京
>>> person('小明',20,'工程師','北京')
Traceback (most recent call last):
File "<pyshell#70>", line 1, in <module>
person('小明',20,'工程師','北京')
TypeError: person() takes 2 positional arguments but 4 were given
參數組合
在定義函數的時候,可以用必選參數、默認參數、可變參數、關鍵字參數和命名參數或者它們的組合。但是參數定義的順序必須是:必選參數、默認參數、可變參數、命名關鍵字參數和關鍵字參數。
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}
還可以使用 tuple 和 dict 調用。任意函數,都可以通過類似 func(args,*kw)的形式調用它,無論參數是怎么定義的:
>>> 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': 88, 'x': '#'}
>>> f2(args, **kw)
a = 1 b = 2 c = 3 d = 88 kw = {'x': '#'}