本文是廖雪峰教程的筆記。
函數(shù)的定義
定義函數(shù)時(shí)衙四,需要確定函數(shù)名和參數(shù)個(gè)數(shù)
def fun(x1,x2,x3):
剔氏;如果有必要,可以先對參數(shù)的數(shù)據(jù)類型做檢查积仗;
函數(shù)體內(nèi)部可以用
return
隨時(shí)返回函數(shù)結(jié)果;函數(shù)執(zhí)行完畢也沒有
return
語句時(shí)蜕猫,自動(dòng)return None
寂曹。函數(shù)可以同時(shí)返回多個(gè)值,但其實(shí)就是一個(gè)
tuple
回右。
函數(shù)的參數(shù)
Python的函數(shù)具有非常靈活的參數(shù)形態(tài)隆圆,既可以實(shí)現(xiàn)簡單的調(diào)用,又可以傳入非常復(fù)雜的參數(shù)翔烁。
默認(rèn)參數(shù)
默認(rèn)參數(shù)可以簡化函數(shù)的調(diào)用渺氧。設(shè)置默認(rèn)參數(shù)時(shí),有幾點(diǎn)要注意:
- 必選參數(shù)在前蹬屹,默認(rèn)參數(shù)在后侣背,否則Python的解釋器會(huì)報(bào)錯(cuò);
- 默認(rèn)參數(shù)降低了函數(shù)調(diào)用的難度慨默,而一旦需要更復(fù)雜的調(diào)用時(shí)贩耐,又可以傳遞更多的參數(shù)來實(shí)現(xiàn)。
- 默認(rèn)參數(shù)一定要用不可變對象厦取,如果是可變對象潮太,程序運(yùn)行時(shí)會(huì)有邏輯錯(cuò)誤!例如:
def add_end(L=[]):
L.append('END')
return L
默認(rèn)參數(shù)L是一個(gè)空list虾攻,是一個(gè)可變對象铡买。當(dāng)使用默認(rèn)參數(shù)調(diào)用時(shí),會(huì)發(fā)現(xiàn)
>>> add_end()
['END']
>>> add_end()
['END', 'END']
>>> add_end()
['END', 'END', 'END']
這顯然是有問題的台谢,要修改上面的例子寻狂,我們可以用None
這個(gè)不變對象來實(shí)現(xiàn):
def add_end(L=None):
if L is None:
L = []
L.append('END')
return L
此時(shí)調(diào)用結(jié)果為
>>> add_end()
['END']
>>> add_end()
['END']
所以,我們在編寫程序時(shí)朋沮,如果可以設(shè)計(jì)一個(gè)不變對象,那就盡量設(shè)計(jì)成不變對象。
可變參數(shù)
- 可變參數(shù)就是傳入的參數(shù)個(gè)數(shù)是可變的樊拓,可以是1個(gè)纠亚、2個(gè)到任意個(gè),還可以是0個(gè)筋夏。
- 定義可變參數(shù)和定義一個(gè)list或tuple參數(shù)相比蒂胞,僅僅在參數(shù)前面加了一個(gè)
*
號。在函數(shù)內(nèi)部条篷,參數(shù)numbers接收到的是一個(gè)tuple骗随,因此,函數(shù)代碼完全不變赴叹。但是鸿染,調(diào)用該函數(shù)時(shí),可以傳入任意個(gè)參數(shù)乞巧,包括0個(gè)參數(shù): - 可變參數(shù)允許你傳入0個(gè)或任意個(gè)參數(shù)涨椒,這些可變參數(shù)在函數(shù)調(diào)用時(shí)自動(dòng)組裝為一個(gè)tuple。 例如:
def calc(*numbers):
sum = 0
for n in numbers:
sum = sum + n * n
return sum
運(yùn)行結(jié)果
>>> calc(1, 2)
5
>>> calc()
0
如果已經(jīng)有一個(gè)list或者tuple绽媒,可以這么調(diào)用可變參數(shù):
>>> nums = [1, 2, 3]
>>> calc(*nums)
14
*nums
表示把nums
這個(gè)list的所有元素作為可變參數(shù)傳進(jìn)去蚕冬。這種寫法相當(dāng)有用,而且很常見是辕。
關(guān)鍵字參數(shù)
- 關(guān)鍵字參數(shù)和可變參數(shù)類似囤热,關(guān)鍵字參數(shù)允許你傳入0個(gè)或任意個(gè)含參數(shù)名的參數(shù),這些關(guān)鍵字參數(shù)在函數(shù)內(nèi)部自動(dòng)組裝為一個(gè)
dict
获三,而可變參數(shù)中自動(dòng)組成一個(gè)tuple
旁蔼。 - 關(guān)鍵字參數(shù)可以擴(kuò)展函數(shù)的功能。試想你正在做一個(gè)用戶注冊的功能石窑,除了用戶名和年齡是必填項(xiàng)外牌芋,其他都是可選項(xiàng),利用關(guān)鍵字參數(shù)來定義這個(gè)函數(shù)就能滿足注冊的需求松逊。例如:
def person(name, age, **kw):
print('name:', name, 'age:', age, 'other:', kw)
運(yùn)行
>>> extra = {'city': 'Beijing', 'job': 'Engineer'}
>>> person('Jack', 24, **extra)
name: Jack age: 24 other: {'city': 'Beijing', 'job': 'Engineer'}
**extra
表示把extra
這個(gè)dict
的所有key-value用關(guān)鍵字參數(shù)傳入到函數(shù)的**kw
參數(shù)躺屁,kw
將獲得一個(gè)dict
,注意kw
獲得的dict
是extra
的一份拷貝经宏,對kw
的改動(dòng)不會(huì)影響到函數(shù)外的extra
犀暑。
命名關(guān)鍵字參數(shù)
- 如果要限制關(guān)鍵字參數(shù)的名字,就可以用命名關(guān)鍵字參數(shù)烁兰,例如:
def person(name, age, *, city, job):
print(name, age, city, job)
和位置參數(shù)不同耐亏,命名關(guān)鍵字參數(shù)必須傳入?yún)?shù)名。調(diào)用方式如下:
>>> person('Jack', 24, city='Beijing', job='Engineer')
Jack 24 Beijing Engineer
和關(guān)鍵字參數(shù)**kw
不同沪斟,命名關(guān)鍵字參數(shù)需要一個(gè)特殊分隔符*
广辰,*
后面的參數(shù)被視為命名關(guān)鍵字參數(shù),前面的參數(shù)是普通的位置參數(shù)。上面定義的函數(shù)就只接收city和job作為關(guān)鍵字參數(shù)择吊。
- 如果函數(shù)定義中已經(jīng)有了一個(gè)可變參數(shù)李根,后面跟著的命名關(guān)鍵字參數(shù)就不再需要一個(gè)特殊分隔符*了:
def person(name, age, *args, city, job):
print(name, age, args, city, job)
上面的函數(shù)定義中,*args
代表可變參數(shù)几睛,跟著的city
房轿,job
是命名關(guān)鍵字參數(shù)。
- 命名關(guān)鍵字參數(shù)可以有缺省值所森,從而簡化調(diào)用:
def person(name, age, *, city='Beijing', job):
print(name, age, city, job)
調(diào)用結(jié)果:
>>> person('Jack', 24, job='Engineer')
Jack 24 Beijing Engineer
參數(shù)組合
- 在Python中定義函數(shù)囱持,可以用必選參數(shù)、默認(rèn)參數(shù)焕济、可變參數(shù)纷妆、關(guān)鍵字參數(shù)和命名關(guān)鍵字參數(shù),這5種參數(shù)都可以組合使用吼蚁。但是請注意凭需,參數(shù)定義的順序必須是:必選參數(shù)、默認(rèn)參數(shù)肝匆、可變參數(shù)粒蜈、命名關(guān)鍵字參數(shù)和關(guān)鍵字參數(shù)。
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中旗国,a
枯怖,b
是必選參數(shù)(位置參數(shù)),c=0
是默認(rèn)參數(shù)能曾,*args
是可變參數(shù)度硝,**kw
是關(guān)鍵字參數(shù);
在f2中,d是命名關(guān)鍵字參數(shù)寿冕。
-
對于任意函數(shù)蕊程,都可以通過類似
func(*args, **kw)
的形式調(diào)用它,無論它的參數(shù)是如何定義的驼唱。例如:
>>> args = (1, 2, 3, 4) #這是一個(gè)tuple
>>> kw = {'d': 99, 'x': '#'} #這是一個(gè)dict
>>> f1(*args, **kw) #*args可以將args中的元素作為可選參數(shù)傳入藻茂,**kw可以將kw中的元素作為key-value形式傳入。
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': '#'}
上面的函數(shù)中玫恳,f1(*args, **kw)
可以看作是f1(args[1],args[2],args[3],args[4], d=kw['d'],x=kw['x'])
f2(*args, **kw)
可以看作f2(args[1],args[2],args[3], d=kw['d'],x=kw['x'])
辨赐。
注意事項(xiàng)總結(jié)
要注意定義可變參數(shù)和關(guān)鍵字參數(shù)的語法:
- *args是可變參數(shù),args接收的是一個(gè)tuple京办;
- **kw是關(guān)鍵字參數(shù)掀序,kw接收的是一個(gè)dict。
以及調(diào)用函數(shù)時(shí)如何傳入可變參數(shù)和關(guān)鍵字參數(shù)的語法:
- 可變參數(shù)既可以直接傳入:
func(1, 2, 3)
惭婿,又可以先組裝list或tuple不恭,再通過*args
傳入:func(*(1, 2, 3))
叶雹;- 關(guān)鍵字參數(shù)既可以直接傳入:
func(a=1, b=2)
,又可以先組裝dict县袱,再通過**kw
傳入:func(**{'a': 1, 'b': 2})
浑娜。
- 使用
*args
和**kw
是Python的習(xí)慣寫法佑力,當(dāng)然也可以用其他參數(shù)名式散,但最好使用習(xí)慣用法。- 命名的關(guān)鍵字參數(shù)是為了限制調(diào)用者可以傳入的參數(shù)名打颤,同時(shí)可以提供默認(rèn)值暴拄。
- 定義命名的關(guān)鍵字參數(shù)在沒有可變參數(shù)的情況下不要忘了寫分隔符*,否則定義的將是位置參數(shù)编饺。