關(guān)于Python函數(shù)參數(shù)的進階用法
1、關(guān)鍵字參數(shù)和位置參數(shù)
關(guān)鍵字參數(shù)(positional argument
)和位置參數(shù)(keyword argument
)
Python
函數(shù)的參數(shù)根據(jù)函數(shù) 在調(diào)用時 (注意,不是函數(shù)定義時)傳參的形式分為關(guān)鍵字參數(shù)和位置參數(shù)。
(1)關(guān)鍵字參數(shù)
關(guān)鍵字參數(shù)是指在函數(shù)調(diào)用傳參時,由標(biāo)識符(如name=
)引導(dǎo)的參數(shù),或者放在一個由**引導(dǎo)的字典里進行傳遞。如下所示:
complex(real=3, imag=5) complex(**{'real': 3, 'imag': 5})
(2)位置參數(shù)
不是關(guān)鍵字參數(shù)的參數(shù)就是位置參數(shù)。它除了單獨傳遞之外,還可以放在一個由*引導(dǎo)的可迭代序列(列表、元組等)里進行傳遞。如下所示:
complex(3, 5) complex(*(3, 5))
位置參數(shù)總是放在函數(shù)的參數(shù)列表最前方,關(guān)鍵字參數(shù)必須要放在位置參數(shù)后面。它們之間的位置關(guān)系如下所示:
def func(arg1, arg2, kwarg1, kwarg2): func(1, 2, kwarg1=3, kwarg2=4)
這里arg1
、arg2
是位置參數(shù),kwarg1
,kwarg2
是關(guān)鍵字參數(shù)。 關(guān)鍵字參數(shù)的key
(也就是這里的 'kwarg1=3'
中的 'kwarg1'
,'kwarg2=4'
中的'kwarg2'
)要保證和形參名稱一致 。
2、接受任意數(shù)量的參數(shù)
(1)接受任意數(shù)量的位置參數(shù)
"*"號表達(dá)式除了上一章我們講的用于對任意長度可迭代對象進行拆分之外, 還能在 函數(shù)定義 中使用,用于定義一個可以接受任意數(shù)量位置參數(shù)的函數(shù),如下所示:
def avg(first, *rest): print(rest) return (first + sum(rest)) / (1 + len(rest)) print(avg(1, 2, 3, 4, 5)) # (2, 3, 4, 5) # 1. 5
"*"開頭的參數(shù)必須做為最后一個位置參數(shù)使用,且"*"開頭的參數(shù)傳進來后是元組數(shù)據(jù)結(jié)構(gòu)。
(2)接受任意數(shù)量的關(guān)鍵字參數(shù)
想接受任意數(shù)量的關(guān)鍵字參數(shù),我們可以類似地使用"**"
開頭的參數(shù)。如下所示:
import html def make_element(name, value, **attrs) -> str: key_values = [ ' %s="%s"' % item for item in attrs.items()] attr_str = ''.join(key_values) # Perform a string formatting operation. element = '<{name} {attrs}>{value}</{name}>'.format(name=name, attrs=attr_str, value=html.escape(value)) return element res_1 = make_element('item', 'Albatross', size='large', quantity=6) res_2 = make_element('p', '<spam>') # escape會把這里'<spam>'中的'<'和'>'替代成安全的序列< > print(res_1) # <item size="large" quantity="6">Albatross</item> print(res_2) # <p ><spam></p>
"**"
開頭的參數(shù)必須做為最后一個關(guān)鍵字參數(shù)使用,且"**"
開頭的參數(shù)傳進來后是字典數(shù)據(jù)結(jié)構(gòu)。
(3)同時接受任意數(shù)量的位置參數(shù)和關(guān)鍵字參數(shù)
如果想要函數(shù)同時接受任意數(shù)量的位置參數(shù)和關(guān)鍵字參數(shù),只要聯(lián)合使用"*"
和"**"
即可。
def anyargs(*args:tuple, **kwargs:dict): print(args) print(kwargs) anyargs(2, 3, 4, 5, time=1, data=2) # (2, 3, 4, 5) # {'time': 1, 'data': 2}
3、keyword-only參數(shù)
前面說過, "*"
打頭的參數(shù)只能做為最后一個位置參數(shù), "**"
打頭的參數(shù)只能做為最后一個關(guān)鍵字參數(shù)(自然也是最后一個參數(shù)),而依此推斷"*"打頭的參數(shù)后的參數(shù)就必然是關(guān)鍵字參數(shù)了。
# 出現(xiàn)在*args之后的參數(shù)稱為keyword-only參數(shù) # 這兩個例子中y都只能是關(guān)鍵字參數(shù),在傳參時要保證key和形參的一致性 def a(x, *args, y): print(y) def b(x, *args, y, **kwargs): print(y) a(4, 6, 7, 8, y=1) b(4, 6, 7, 3, y=1, data=2, year=3) # 1 # 1
這樣的參數(shù)稱為keyword-only
參數(shù),即出現(xiàn)在*args
之后的參數(shù)只能做為關(guān)鍵字參數(shù)使用。
我們可以充分利用這一性質(zhì),將關(guān)鍵字參數(shù)放在以*打頭的參數(shù)后,或者一個單獨的*之后,強迫函數(shù)的調(diào)用者必須傳關(guān)鍵字參數(shù),比如下面這樣:
def recv(max_size, *, block): 'Receives a message' pass recv(1024, True) # recv2() takes 1 positional argument but 2 were given # and missing 1 required keyword-only argument: 'block' recv(1024, block=True) # OK
這項技術(shù)在實際項目中,可以用來為接受任意數(shù)量的位置參數(shù)的函數(shù)來指定關(guān)鍵字參數(shù),比如下面這個帶截斷功能的求最小值函數(shù)。這里的clip
參數(shù)被強迫為必須按照關(guān)鍵字參數(shù)傳入,而且設(shè)定了一個默認(rèn)值None
, 使參數(shù)為可選的。如下所示:
def mininum(*values, clip=None): m = min(values) if clip is not None: m = clip if clip > m else m return m res1 = mininum(1, 5, 2, -5, 10) res2 = mininum(1, 5, 2, -4, 10, clip=0) print(res1, res2) # -5, 0
除此之外,keyword-only
參數(shù)可以提高代碼可讀性,像下面這種函數(shù)寫法:
msg = recv(1024, False)
如果代碼的閱讀者不熟悉recv
函數(shù)的工作方式,那么可能不太明白這里的False
參數(shù)有什么作用,如果這個函數(shù)的調(diào)用可以寫成下面這樣的話,那就清晰多了(當(dāng)然,需要這個函數(shù)的編寫者最開始就強制函數(shù)的使用者這樣寫):
msg = recv(1024, block=False)
最后,如果 函數(shù)定義 的的時候強制使用了keyword-only
參數(shù),那么當(dāng)用戶請求幫助信息時,參數(shù)信息可以很自然地顯現(xiàn)出來:
print(help(recv)) # Help on function recv in module __main__: # recv(max_size, *_, block) # Receives a message
3、可選參數(shù)(帶默認(rèn)值的參數(shù))
要想定義一個可選參數(shù),需要在 函數(shù)定義 中為參數(shù)賦值,并保證默認(rèn)參數(shù)出現(xiàn)在參數(shù)列表最后。像下面這樣:
def spam(a, b=42): print(a, b) spam(1) # 1, 42 spam(1, 2) # 1, 2
如果默認(rèn)值是可變?nèi)萜鳎热缯f列表、集合、字典等,需要把None
做為默認(rèn)值:如下所示:
def spam(a, b=None): if b is None: b = []
警示1:千萬不能直接像下面這樣寫:
def spam(a, b=[]):
如果像上面那樣寫,那么就會發(fā)生一些你所不期望看到的現(xiàn)象:如果默認(rèn)值在函數(shù)體之外被修改了,那么這種修改在之后的函數(shù)調(diào)用中仍然陰魂不散,如下面所示:
def spam(a, b=[]): print(b) return b x = spam(1) x.append('oh!') x.append('no!') print(x) spam(1) # [] # ['oh!', 'no!'] # ['oh!', 'no!']
警示2:在函數(shù)體中,我們常常需要判斷參數(shù)是否為None,此處需要使用is運算符,千萬不能直接像下面這樣寫:
def spam(a, b=None): if not b: b = []
這里的問題在于:盡管None
會被判定為False
,可還有其他許多對象(比如長度為0的字符串、列表、元組、字典等)也存在這樣的行為。這樣,有很多其他的特定輸入也會被判定為False,然后本該是用戶傳進來的值直接被默認(rèn)的[]覆蓋掉了。如下所示:
def spam(a, b=None): if not b: b = [] spam(1) # OK x = [] spam(1, x) # Oops! x will be overwritten by default [] spam(1, 0) # Oops! 0 will be overwritten by default [] spam(1, '') # Oops! '' will be overwritten by default []
最后,我們再來討論一個非常棘手的問題。我們想要在函數(shù)中檢測調(diào)用者是否對可選參數(shù)提供了某個特定值(可以是任意值,None
也算)這樣,我們自然就不能用None
,0
, False
當(dāng)做默認(rèn)值然后再來做檢測了,因為用戶本身就可能拿它們當(dāng)做參數(shù)。
要解決這個問題,可以像下面這樣寫:
_no_value = object() def spam(a, b=_no_value): if b == _no_value: print("No b value supplied") return print(a, b) spam(1) # No b value supplied spam(1, 2) # 1 2 spam(1, None) # 1 None
這里_no_value
是基于object()
類創(chuàng)建的一個獨有對象,可以用這個來對用戶提供的參數(shù)做檢測,因為用戶幾乎不可能把_no_value
對象做為參數(shù)輸入(除非用戶傳入的是相同的對象,否則哪怕是object
類型的另一個對象都和_no_value
對象是不同的)。
這里簡要說明一下object
類,object
是Python
中幾乎所有對象的基類,object
對象沒有任何數(shù)據(jù)(底層缺少__dict__
字典,甚至沒辦法設(shè)置任何屬性),它唯一的作用就是用來檢測相等性。
到此這篇關(guān)于關(guān)于Python函數(shù)參數(shù)的進階用法的文章就介紹到這了,更多相關(guān)Python函數(shù)參數(shù)內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
淺談keras 的抽象后端(from keras import backend as K)
這篇文章主要介紹了淺談keras 的抽象后端(from keras import backend as K),具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-06-06Python 3.x 安裝opencv+opencv_contrib的操作方法
下面小編就為大家分享一篇Python 3.x 安裝opencv+opencv_contrib的操作方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2018-04-04關(guān)于Python中的if __name__ == __main__詳情
在學(xué)習(xí)Python的過程中發(fā)現(xiàn)即使把if __name__ == ‘__main__’ 去掉,程序還是照樣運行。很多小伙伴只知道是這么用的,也沒有深究具體的作用。這篇文字就來介紹一下Python中的if __name__ == ‘__main__’的作用,需要的朋友參考下文2021-09-09python使用xlrd與xlwt對excel的讀寫和格式設(shè)定
最近在用python處理excel表的時候出現(xiàn)了一些問題,所以想著記錄下最后的實現(xiàn)方式和問題解決方法。方便自己或者大家在有需要的時候參考借鑒,下面這篇文章主要就介紹了python使用xlrd與xlwt對excel的讀寫和格式設(shè)定的相關(guān)資料,一起來學(xué)習(xí)學(xué)習(xí)吧。2017-01-01關(guān)于keras多任務(wù)多l(xiāng)oss回傳的思考
這篇文章主要介紹了關(guān)于keras多任務(wù)多l(xiāng)oss回傳的思考,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-05-05