您好,登錄后才能下訂單哦!
今天小編給大家分享一下Python定義函數輸入參數的規則有哪些的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。
函數參數即為函數的輸入,可分類為五組。
位置或關鍵字參數:同時允許位置和關鍵字參數;
可變位置參數:在元組中收集任意數量的位置參數;
可變關鍵字參數:在字典中收集任意數量的關鍵字參數;
僅限位置參數:只能作為位置參數傳遞;
僅限關鍵字參數:只能作為關鍵字參數傳遞。
除了我們在這里看到的類別之外,參數還可以分為必選項和可選項。可選參數有默認值,其值在函數定義中指定。語法是格式為:name=value。示例如下:
# 定義參數有默認值的函數,調用時其為可選型參數 def func(a, b=4, c=88): print(a, b, c) func(1) # prints: 1 4 88 func(b=5, a=7, c=9) # prints: 7 5 9 func(42, c=9) # prints: 42 4 9 func(42, 43, 44) # prints: 42, 43, 44
這里,a是必需傳遞參數項,而b的默認值是4,c的默認值是88,兩者是可選項。重要的是要注意,除了只有關鍵字的形參外,必需型形參必須始終位于函數定義中所有可選形參的左側。試著在上面的例子中刪除c的默認值,看看會發生什么。
有時,可能不希望為函數指定位置參數的確切數量,而Python通過使用可變位置參數提供了實現這一點的能力。讓我們來看一個非常常見的用例,minimum()函數。
這是一個計算其輸入值最小值的函數,代碼如下:
# 不定量位置參數 def minimum(*n): # print(type(n)) # n 是個元組 if n: # mn = n[0] for value in n[1:]: if value < mn: mn = value print(mn) minimum(1, 3, -7, 9) # n = (1, 3, -7, 9) - prints: -7 minimum() # n = () - prints: nothing
如上所見,當我們定義一個帶有星號*的形參時,我們是在告訴Python,當函數被調用時,這個形參將收集數量不定的位置實參。在函數中,n是一個元組。可取消代碼中的注釋print(type(n))行,然后運行程序并看看輸出。
注意,一個函數最多只能有一個不定量位置參數——有更多的位置參數是沒有意義的。Python將無法決定如何劃分它們之間的參數。您也無法為變量位置參數指定默認值。默認值總是一個空元組。
提示:
是否注意到代碼中是如何用一個簡單的if n:檢查n是否為空的?這是因為在Python中,集合對象在非空時求值為True,否則為False。元組、集合、列表、字典等等都是如此。
另一件需要注意的事情是,當調用不帶參數的函數時,可能想拋出一個錯誤,而不是靜默地什么都不做。在這種情況下,我們不關心如何使這個函數健壯,而是要理解可變量位置參數。
另外,是否注意到,定義不定量位置形參的語法與可迭代解包的語法非常相似?這并非巧合。畢竟,這兩個特征互為鏡像。它們也經常一起使用,因為不定量位置形參讓你不必擔心解包的可迭代對象的長度是否與函數定義中的形參數量相匹配。
不定量關鍵字參數(Variable keyword parameters)非常類似于不定量位置參數。唯一的區別是語法(**而不是*)和它們以字典形式被收集的事實:
# 不定量關鍵字參數 def func(**kwargs): print(kwargs) func(a=1, b=42) # prints {'a': 1, 'b': 42} func() # prints {} func(a=1, b=46, c=99) # prints {'a': 1, 'b': 46, 'c': 99}
如上所示,在函數定義的參數名稱前添加**告訴Python使用該名稱來收集數量不定的關鍵字參數。與不定量位置參數的情況一樣,每個函數最多只能有一個可變關鍵字參數,并且不能指定默認值。
就像可變量位置參數類似于可迭代解包一樣,可變關鍵字參數類似于字典解包。字典解包也經常用于將參數傳遞給具有可變量關鍵字形參的函數。
為什么能夠傳遞可變數量的關鍵字參數如此重要,目前可能還不清楚,那么通過如何使用這一能力的示例,你將能更真實的理解其重要性。
我們定義一個連接到數據庫的函數:我們希望通過不帶參數地調用這個函數來連接到默認數據庫。還希望通過向函數傳遞適當的參數來連接到任何其他數據庫。在你繼續讀下去之前,自己試著花幾分鐘自己想出一個解決方案:
# 可變量關鍵字參數 def connect(**options): conn_params = { 'host': options.get('host', '127.0.0.1'), 'port': options.get('port', 5432), 'user': options.get('user', ''), 'pwd': options.get('pwd', ''), } print(conn_params) # 然后連接數據庫(注釋掉的代碼行) # db.connect(**conn_params) connect() connect(host='127.0.0.42', port=5433) connect(port=5431, user='admin', pwd='super')
注意,在函數中,我們可以準備一個連接參數字典(conn_params)使用默認值作為回退,其允許在函數調用時提供以覆蓋它們。有更好的方法可以用更少的代碼行來實現這一點,但我們現在不關心這一點。運行上述代碼會得到以下結果:
{'a': 1, 'b': 46, 'c': 99} {'host': '127.0.0.1', 'port': 5432, 'user': '', 'pwd': ''} {'host': '127.0.0.42', 'port': 5433, 'user': '', 'pwd': ''} {'host': '127.0.0.1', 'port': 5431, 'user': 'admin', 'pwd': 'super'}
注意函數調用和輸出之間的對應關系,以及如何根據傳遞給函數的內容重寫默認值。
從Python 3.8開始,PEP 570引入了僅限位置的參數。有一種新的函數參數語法,/,表示一組函數形參必須在位置上指定,不能作為關鍵字參數傳遞。讓我們看一個簡單的例子:
# 僅限位置參數 def func(a, b, /, c): print(a, b, c) func(1, 2, 3) # prints: 1 2 3 func(1, 2, c=3) # prints 1 2 3
在上面的例子中,我們定義了一個函數func(),它指定了三個參數:a、b和c。函數簽名中的/表示a和b必須按位置傳遞,也就是說,不能通過關鍵字傳遞。
示例中的最后兩行顯示,我們可以按位置傳遞所有三個參數來調用函數,或者可以按關鍵字傳遞c。這兩種情況都可以正常工作,因為c定義在函數簽名中的/之后。如果我們試圖通過通過關鍵字傳遞a或b來調用函數,像這樣:
func(1, b=2, c=3)
這將產生如下類似回溯跟蹤信息:
Traceback (most recent call last): File "……", line 9, infunc(1, b=2, c=3) TypeError: func() got some positional-only arguments passed as keyword arguments: 'b'
前面的例子告訴我們,Python現在反饋給我們調用func()的方式,其意思是:通過關鍵字傳遞了參數b,但不允許這樣做。
僅限位置參數也可以是可選的,如下所示:
# 可選的僅限位置參數 def func(a, b=2, /): print(a, b) func(4, 5) # prints 4 5 func(3) # prints 3 2
通過一些從官方文檔中借來的例子來看看這個特性給該語言帶來了什么。一個優點是能夠完全模擬現有C編碼函數的行為:
def divmod(a, b, /): "模擬內建函數 divmod()" return (a // b, a % b)
另一個重要的用例是在形參名沒有啥有意義的幫助的情況下排除關鍵字實參:
len(obj='hello')
在上面的例子中,obj關鍵字參數降低了可讀性。此外,如果我們希望重構len函數的內部結構,并將obj重命名為the_object(或任何其他名稱),更改保證不會破壞任何客戶端代碼,因為不會有任何對len()函數的調用,會涉及到現在已經過時的obj參數名稱。
最后,使用僅限位置形參意味著/左邊的任何值都可以在不定量關鍵字實參中使用,如下例所示:
def func_name(name, /, **kwargs): print(name) print(kwargs) func_name('Positional-only name', name='Name in **kwargs') # 打印輸出為: # Positional-only name # {'name': 'Name in **kwargs'}
在函數簽名中保留參數名以便在**kwargs中使用的能力可以生成更簡單、更清晰的代碼。
現在來研究一下僅限位置類似版:僅限關鍵字參數。
Python 3引入了僅限關鍵字的參數。我們只簡要地研究它們,因為它們的用例并不常見。有兩種方法可以指定它們,要么在不定量位置參數之后,要么在不定的*之后。來看兩個例子。代碼如下:
# 僅限關鍵字參數 def kwo(*a, c): print(a, c) kwo(1, 2, 3, c=7) # prints: (1, 2, 3) 7 kwo(c=4) # prints: () 4 # kwo(1, 2) # 此行出問題——無效于法,并有如下錯誤 # TypeError: kwo() missing 1 required keyword-only argument: 'c' def kwo2(a, b=42, *, c): print(a, b, c) kwo2(3, b=7, c=99) # prints: 3 7 99 kwo2(3, c=13) # prints: 3 42 13 # kwo2(3, 23) # 此行出問題——無效于法,并有如下錯誤 # TypeError: kwo2() missing 1 required keyword-only argument: 'c'
正如預期的那樣,函數kwo()接受數量可變的位置參數(a)和一個只有關鍵字的關鍵字c。調用的結果很簡單,你可以取消對第三個調用的注釋,以查看Python返回什么錯誤。
同樣的情況也適用于函數kwo2(),它與kwo的不同之處在于,它接受一個位置參數a、一個關鍵字參數b和一個只有關鍵字的參數c。你可以取消對第三個調用的注釋,以查看產生的錯誤。
現在應已知道了如何指定不同類型的輸入參數,接下來看看如何在函數定義中組合它們。
可以在同一個函數中組合不同的參數類型(事實上,這樣做通常非常有用)。就像在同一個函數調用中組合不同類型的實參一樣,在順序上有一些限制:
僅限位置的參數放在前面,然后跟隨一個斜杠“/”。
普通參數在任何僅限位置參數之后。
不定量位置參數在正常參數之后。
只有關鍵字參數在不定量位置參數之后。
不定量關鍵字參數總是排在最后。
對于僅限位置參數和普通參數,任何必需的參數必須在任何可選參數之前定義。這意味著,如果你有一個可選的僅限位置參數,那么所有常規參數也必須是可選的。該規則不影響僅限關鍵字的參數。
如果沒有例子,這些規則可能會有點難以理解,所以來看幾個示例:
# 定義個帶有所有參數形式的函數 def func(a, b, c=7, *args, **kwargs): print('a, b, c:', a, b, c) print('args:', args) print('kwargs:', kwargs) func(1, 2, 3, 5, 7, 9, A='a', B='b')
注意函數定義中參數的順序。執行該程序會得到以下結果:
a, b, c: 1 2 3 args: (5, 7, 9) kwargs: {'A': 'a', 'B': 'b'}
現在再來看一個只有關鍵字參數的例子:
# 僅限觀自在參數 def allparams(a, /, b, c=42, *args, d=256, e, **kwargs): print('a, b, c:', a, b, c) print('d, e:', d, e) print('args:', args) print('kwargs:', kwargs) allparams(1, 2, 3, 4, 5, 6, e=7, f=9, g=10)
注意,在函數聲明中有僅限位置形參和僅限關鍵字形參:a僅限位置形參,而d和e僅限關鍵字形參。他們是在*args可變量位置參數之后,如果它們緊跟在單個*的后面,也會是一樣的(在這種情況下,將沒有任何可變位置參數)。運行程序會得到以下結果:
a, b, c: 1 2 3 d, e: 256 7 args: (4, 5, 6) kwargs: {'f': 9, 'g': 10}
另一件需要注意的事情是我們為可變量位置參數和關鍵字參數命名。你可以自由選擇不同的名稱,但請注意,args和kwargs是這些參數的常規名稱,至少在一般情況下是這樣。
為了簡要回顧一下使用僅限位置和關鍵字說明符的函數簽名,下面是一些進一步的示例。省略不定量位置和關鍵字參數,為簡潔起見,我們只剩下以下語法:
def xxxFuncName(positional_only_parameters, /, positional_or_keyword_parameters, *, keyword_only_parameters): # 函數體 pass
首先,我們有僅限位置的參數,然后是位置或關鍵字參數,最后是僅限關鍵字參數。
其他一些有效簽名如下:
def xxxFuncName(p1, p2, /, p_or_kw, *, kw): def xxxFuncName(p1, p2=None, /, p_or_kw=None, *, kw): def xxxFuncName(p1, p2=None, /, *, kw): def xxxFuncName(p1, p2=None, /): def xxxFuncName(p1, p2, /, p_or_kw): def xxxFuncName(p1, p2, /):
以上均為有效簽名,下列為無效簽名:
def xxxFuncName(p1, p2=None, /, p_or_kw, *, kw): def xxxFuncName(p1=None, p2, /, p_or_kw=None, *, kw): def xxxFuncName(p1=None, p2, /):
提示:在這一點上,要很好的理解與掌握,一個有用的練習方法是實現上述示例簽名中的任何一個,打印出這些參數的值,就像我們在前面的練習中所做的那樣,并以不同的方式傳遞參數。
要注意的一件事是,在Python中,默認值是在定義時創建的;因此,根據默認值的可變性,對同一函數的后續調用可能會有不同的行為。讓我們看一個例子:
# 帶有可變默認值參數函數 def func(a=[], b={}): print(a) print(b) print('#' * 12) a.append(len(a)) # 影響a的默認值 b[len(a)] = len(a) # 影響b的默認值 func() func() func()
兩個參數都有可變的默認值。這意味著,如果執行中影響了這些對象,任何修改都將停留在后續的函數調用中。看看你是否能理解這些調用的輸出:
[] {} ############ [0] {1: 1} ############ [0, 1] {1: 1, 2: 2} ############
是不是很搞事?雖然這種行為一開始看起來很奇怪,但它實際上是有意義的,而且非常方便——例如,當使用“記憶”技術時,就有了天生之才的傲嬌。更有趣的是,在調用之間,我們引入了一個不使用默認值的函數,比如:
# 中間調停者調用 func() func(a=[1, 2, 3], b={'B': 1}) func()
運行代碼輸出內容如下所示:
[] {} ############ [1, 2, 3] {'B': 1} ############ [0] {1: 1} ############
這個輸出告訴我們,即使使用其他值調用函數,默認值也會被保留。我想到的一個問題是,如何每次都獲得一個新的空值?慣例是這樣的:
# 無陷阱可變缺省默認值 def func(a=None): if a is None: a = [] # 干些使用a的工作 ...
注意,通過使用前面的技術,如果調用函數時沒有傳遞a,我們總是得到一個全新的空列表。
以上就是“Python定義函數輸入參數的規則有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。