溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Python定義函數(shù)輸入?yún)?shù)的規(guī)則有哪些

發(fā)布時間:2023-05-04 09:34:42 來源:億速云 閱讀:118 作者:zzz 欄目:編程語言

今天小編給大家分享一下Python定義函數(shù)輸入?yún)?shù)的規(guī)則有哪些的相關(guān)知識點,內(nèi)容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

函數(shù)參數(shù)即為函數(shù)的輸入,可分類為五組。

  • 位置或關(guān)鍵字參數(shù):同時允許位置和關(guān)鍵字參數(shù);

  • 可變位置參數(shù):在元組中收集任意數(shù)量的位置參數(shù);

  • 可變關(guān)鍵字參數(shù):在字典中收集任意數(shù)量的關(guān)鍵字參數(shù);

  • 僅限位置參數(shù):只能作為位置參數(shù)傳遞;

  • 僅限關(guān)鍵字參數(shù):只能作為關(guān)鍵字參數(shù)傳遞。

1.可選參數(shù)

除了我們在這里看到的類別之外,參數(shù)還可以分為必選項和可選項??蛇x參數(shù)有默認值,其值在函數(shù)定義中指定。語法是格式為:name=value。示例如下:

# 定義參數(shù)有默認值的函數(shù),調(diào)用時其為可選型參數(shù)
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是必需傳遞參數(shù)項,而b的默認值是4,c的默認值是88,兩者是可選項。重要的是要注意,除了只有關(guān)鍵字的形參外,必需型形參必須始終位于函數(shù)定義中所有可選形參的左側(cè)。試著在上面的例子中刪除c的默認值,看看會發(fā)生什么。

2.不定量位置參數(shù)

有時,可能不希望為函數(shù)指定位置參數(shù)的確切數(shù)量,而Python通過使用可變位置參數(shù)提供了實現(xiàn)這一點的能力。讓我們來看一個非常常見的用例,minimum()函數(shù)。

這是一個計算其輸入值最小值的函數(shù),代碼如下:

# 不定量位置參數(shù)
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,當函數(shù)被調(diào)用時,這個形參將收集數(shù)量不定的位置實參。在函數(shù)中,n是一個元組??扇∠a中的注釋print(type(n))行,然后運行程序并看看輸出。

注意,一個函數(shù)最多只能有一個不定量位置參數(shù)——有更多的位置參數(shù)是沒有意義的。Python將無法決定如何劃分它們之間的參數(shù)。您也無法為變量位置參數(shù)指定默認值。默認值總是一個空元組。

提示:

是否注意到代碼中是如何用一個簡單的if n:檢查n是否為空的?這是因為在Python中,集合對象在非空時求值為True,否則為False。元組、集合、列表、字典等等都是如此。

另一件需要注意的事情是,當調(diào)用不帶參數(shù)的函數(shù)時,可能想拋出一個錯誤,而不是靜默地什么都不做。在這種情況下,我們不關(guān)心如何使這個函數(shù)健壯,而是要理解可變量位置參數(shù)。

另外,是否注意到,定義不定量位置形參的語法與可迭代解包的語法非常相似?這并非巧合。畢竟,這兩個特征互為鏡像。它們也經(jīng)常一起使用,因為不定量位置形參讓你不必擔心解包的可迭代對象的長度是否與函數(shù)定義中的形參數(shù)量相匹配。

3.不定量關(guān)鍵字參數(shù)

不定量關(guān)鍵字參數(shù)(Variable keyword parameters)非常類似于不定量位置參數(shù)。唯一的區(qū)別是語法(**而不是*)和它們以字典形式被收集的事實:

# 不定量關(guān)鍵字參數(shù)
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}

如上所示,在函數(shù)定義的參數(shù)名稱前添加**告訴Python使用該名稱來收集數(shù)量不定的關(guān)鍵字參數(shù)。與不定量位置參數(shù)的情況一樣,每個函數(shù)最多只能有一個可變關(guān)鍵字參數(shù),并且不能指定默認值。

就像可變量位置參數(shù)類似于可迭代解包一樣,可變關(guān)鍵字參數(shù)類似于字典解包。字典解包也經(jīng)常用于將參數(shù)傳遞給具有可變量關(guān)鍵字形參的函數(shù)。

為什么能夠傳遞可變數(shù)量的關(guān)鍵字參數(shù)如此重要,目前可能還不清楚,那么通過如何使用這一能力的示例,你將能更真實的理解其重要性。

我們定義一個連接到數(shù)據(jù)庫的函數(shù):我們希望通過不帶參數(shù)地調(diào)用這個函數(shù)來連接到默認數(shù)據(jù)庫。還希望通過向函數(shù)傳遞適當?shù)膮?shù)來連接到任何其他數(shù)據(jù)庫。在你繼續(xù)讀下去之前,自己試著花幾分鐘自己想出一個解決方案:

# 可變量關(guān)鍵字參數(shù)
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)

# 然后連接數(shù)據(jù)庫(注釋掉的代碼行)
# db.connect(**conn_params)
connect()
connect(host='127.0.0.42', port=5433)
connect(port=5431, user='admin', pwd='super')

注意,在函數(shù)中,我們可以準備一個連接參數(shù)字典(conn_params)使用默認值作為回退,其允許在函數(shù)調(diào)用時提供以覆蓋它們。有更好的方法可以用更少的代碼行來實現(xiàn)這一點,但我們現(xiàn)在不關(guān)心這一點。運行上述代碼會得到以下結(jié)果:

{'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'}

注意函數(shù)調(diào)用和輸出之間的對應(yīng)關(guān)系,以及如何根據(jù)傳遞給函數(shù)的內(nèi)容重寫默認值。

4.僅限位置參數(shù)

從Python 3.8開始,PEP 570引入了僅限位置的參數(shù)。有一種新的函數(shù)參數(shù)語法,/,表示一組函數(shù)形參必須在位置上指定,不能作為關(guān)鍵字參數(shù)傳遞。讓我們看一個簡單的例子:

# 僅限位置參數(shù)
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

在上面的例子中,我們定義了一個函數(shù)func(),它指定了三個參數(shù):a、b和c。函數(shù)簽名中的/表示a和b必須按位置傳遞,也就是說,不能通過關(guān)鍵字傳遞。

示例中的最后兩行顯示,我們可以按位置傳遞所有三個參數(shù)來調(diào)用函數(shù),或者可以按關(guān)鍵字傳遞c。這兩種情況都可以正常工作,因為c定義在函數(shù)簽名中的/之后。如果我們試圖通過通過關(guān)鍵字傳遞a或b來調(diào)用函數(shù),像這樣:

func(1, b=2, c=3)

這將產(chǎn)生如下類似回溯跟蹤信息:

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現(xiàn)在反饋給我們調(diào)用func()的方式,其意思是:通過關(guān)鍵字傳遞了參數(shù)b,但不允許這樣做。

僅限位置參數(shù)也可以是可選的,如下所示:

# 可選的僅限位置參數(shù)
def func(a, b=2, /):
print(a, b)

func(4, 5) # prints 4 5
func(3) # prints 3 2

通過一些從官方文檔中借來的例子來看看這個特性給該語言帶來了什么。一個優(yōu)點是能夠完全模擬現(xiàn)有C編碼函數(shù)的行為:

def divmod(a, b, /):
"模擬內(nèi)建函數(shù) divmod()"
return (a // b, a % b)

另一個重要的用例是在形參名沒有啥有意義的幫助的情況下排除關(guān)鍵字實參:

len(obj='hello')

在上面的例子中,obj關(guān)鍵字參數(shù)降低了可讀性。此外,如果我們希望重構(gòu)len函數(shù)的內(nèi)部結(jié)構(gòu),并將obj重命名為the_object(或任何其他名稱),更改保證不會破壞任何客戶端代碼,因為不會有任何對len()函數(shù)的調(diào)用,會涉及到現(xiàn)在已經(jīng)過時的obj參數(shù)名稱。

最后,使用僅限位置形參意味著/左邊的任何值都可以在不定量關(guān)鍵字實參中使用,如下例所示:

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'}

在函數(shù)簽名中保留參數(shù)名以便在**kwargs中使用的能力可以生成更簡單、更清晰的代碼。

現(xiàn)在來研究一下僅限位置類似版:僅限關(guān)鍵字參數(shù)。

5.僅限關(guān)鍵字參數(shù)

Python 3引入了僅限關(guān)鍵字的參數(shù)。我們只簡要地研究它們,因為它們的用例并不常見。有兩種方法可以指定它們,要么在不定量位置參數(shù)之后,要么在不定的*之后。來看兩個例子。代碼如下:

# 僅限關(guān)鍵字參數(shù)
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'

正如預(yù)期的那樣,函數(shù)kwo()接受數(shù)量可變的位置參數(shù)(a)和一個只有關(guān)鍵字的關(guān)鍵字c。調(diào)用的結(jié)果很簡單,你可以取消對第三個調(diào)用的注釋,以查看Python返回什么錯誤。

同樣的情況也適用于函數(shù)kwo2(),它與kwo的不同之處在于,它接受一個位置參數(shù)a、一個關(guān)鍵字參數(shù)b和一個只有關(guān)鍵字的參數(shù)c。你可以取消對第三個調(diào)用的注釋,以查看產(chǎn)生的錯誤。

現(xiàn)在應(yīng)已知道了如何指定不同類型的輸入?yún)?shù),接下來看看如何在函數(shù)定義中組合它們。

6.組合輸入?yún)?shù)

可以在同一個函數(shù)中組合不同的參數(shù)類型(事實上,這樣做通常非常有用)。就像在同一個函數(shù)調(diào)用中組合不同類型的實參一樣,在順序上有一些限制:

  • 僅限位置的參數(shù)放在前面,然后跟隨一個斜杠“/”。

  • 普通參數(shù)在任何僅限位置參數(shù)之后。

  • 不定量位置參數(shù)在正常參數(shù)之后。

  • 只有關(guān)鍵字參數(shù)在不定量位置參數(shù)之后。

  • 不定量關(guān)鍵字參數(shù)總是排在最后。

對于僅限位置參數(shù)和普通參數(shù),任何必需的參數(shù)必須在任何可選參數(shù)之前定義。這意味著,如果你有一個可選的僅限位置參數(shù),那么所有常規(guī)參數(shù)也必須是可選的。該規(guī)則不影響僅限關(guān)鍵字的參數(shù)。

如果沒有例子,這些規(guī)則可能會有點難以理解,所以來看幾個示例:

# 定義個帶有所有參數(shù)形式的函數(shù)
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')

注意函數(shù)定義中參數(shù)的順序。執(zhí)行該程序會得到以下結(jié)果:

a, b, c: 1 2 3
args: (5, 7, 9)
kwargs: {'A': 'a', 'B': 'b'}

現(xiàn)在再來看一個只有關(guān)鍵字參數(shù)的例子:

# 僅限觀自在參數(shù)
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)

注意,在函數(shù)聲明中有僅限位置形參和僅限關(guān)鍵字形參:a僅限位置形參,而d和e僅限關(guān)鍵字形參。他們是在*args可變量位置參數(shù)之后,如果它們緊跟在單個*的后面,也會是一樣的(在這種情況下,將沒有任何可變位置參數(shù))。運行程序會得到以下結(jié)果:

a, b, c: 1 2 3
d, e: 256 7
args: (4, 5, 6)
kwargs: {'f': 9, 'g': 10}

另一件需要注意的事情是我們?yōu)榭勺兞课恢脜?shù)和關(guān)鍵字參數(shù)命名。你可以自由選擇不同的名稱,但請注意,args和kwargs是這些參數(shù)的常規(guī)名稱,至少在一般情況下是這樣。

7.更多的簽名示例

為了簡要回顧一下使用僅限位置和關(guān)鍵字說明符的函數(shù)簽名,下面是一些進一步的示例。省略不定量位置和關(guān)鍵字參數(shù),為簡潔起見,我們只剩下以下語法:

def xxxFuncName(positional_only_parameters, /,
 positional_or_keyword_parameters, *,
 keyword_only_parameters):
# 函數(shù)體
pass

首先,我們有僅限位置的參數(shù),然后是位置或關(guān)鍵字參數(shù),最后是僅限關(guān)鍵字參數(shù)。

其他一些有效簽名如下:

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, /):

提示:在這一點上,要很好的理解與掌握,一個有用的練習(xí)方法是實現(xiàn)上述示例簽名中的任何一個,打印出這些參數(shù)的值,就像我們在前面的練習(xí)中所做的那樣,并以不同的方式傳遞參數(shù)。

8.避免陷阱!可變默認值

要注意的一件事是,在Python中,默認值是在定義時創(chuàng)建的;因此,根據(jù)默認值的可變性,對同一函數(shù)的后續(xù)調(diào)用可能會有不同的行為。讓我們看一個例子:

# 帶有可變默認值參數(shù)函數(shù)
def func(a=[], b={}):
print(a)
print(b)
print('#' * 12)
a.append(len(a)) # 影響a的默認值
b[len(a)] = len(a) # 影響b的默認值

func()
func()
func()

兩個參數(shù)都有可變的默認值。這意味著,如果執(zhí)行中影響了這些對象,任何修改都將停留在后續(xù)的函數(shù)調(diào)用中??纯茨闶欠衲芾斫膺@些調(diào)用的輸出:

[]
{}
############
[0]
{1: 1}
############
[0, 1]
{1: 1, 2: 2}
############

是不是很搞事?雖然這種行為一開始看起來很奇怪,但它實際上是有意義的,而且非常方便——例如,當使用“記憶”技術(shù)時,就有了天生之才的傲嬌。更有趣的是,在調(diào)用之間,我們引入了一個不使用默認值的函數(shù),比如:

# 中間調(diào)停者調(diào)用
func()
func(a=[1, 2, 3], b={'B': 1})
func()

運行代碼輸出內(nèi)容如下所示:

[]
{}
############
[1, 2, 3]
{'B': 1}
############
[0]
{1: 1}
############

這個輸出告訴我們,即使使用其他值調(diào)用函數(shù),默認值也會被保留。我想到的一個問題是,如何每次都獲得一個新的空值?慣例是這樣的:

# 無陷阱可變?nèi)笔∧J值
def func(a=None):
if a is None:
a = []
# 干些使用a的工作 ...

注意,通過使用前面的技術(shù),如果調(diào)用函數(shù)時沒有傳遞a,我們總是得到一個全新的空列表。

以上就是“Python定義函數(shù)輸入?yún)?shù)的規(guī)則有哪些”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學(xué)習(xí)更多的知識,請關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI