Python-函數定義詳解


函數定義支持可變數量的參數。下面列出三種可以組合使用的形式。

1 默認值參數

為參數指定默認值,在調用函數時可以使用比定義時更少的參數。

def student_info(name, sex, age=18, score=100):
    if sex == 'male':
        print(f"{name} is {age} years old, his score is {score}")
    else:
        print(f"{name} is {age} years old, her score is {score}")

該函數接收兩個必選參數namesex ,兩個可選參數 agescore 。該函數可用下列方式調用

  • 只傳入必選參數
student_info('ZhangSan', 'male')
# zhangSan is 18 years old, his score is 100.
  • 傳入一個可選參數
student_info('LiSi', 'female', 17)
# LiSi is 17 years old, her score is 100.
  • 傳入所有實參
student_info('XiaoHong', 'female', 17, 99)
# XiaoHong is 17 years old, her score is 99.

2 關鍵字參數

kwarg=value 形式的 關鍵字參數 也可以用於調用函數。

def student_info(name, sex, age=18, score=100):
    if sex == 'male':
        print(f"{name} is {age} years old, his score is {score}")
    else:
        print(f"{name} is {age} years old, her score is {score}")

使用了默認值參數的函數都可以通過kwarg=value 形式的關鍵字參數調用函數。該函數可以通過下列方式調用。

student_info('ZhangSan', 'male')
student_info('ZhangSan', 'male', age=17)
student_info('ZhangSan', 'male', score=99)
student_info('ZhangSan', 'male', age=19, score=98)
student_info('ZhangSan', 'male', score=95, age=20)

從上面調用函數的方式可以看出:

  • 關鍵字參數的順序可以和定義的順序不一致
  • 關鍵字參數必須放在位置參數之后

如果你想打亂所有參數的順序,包括位置參數,那么你需要對所有參數使用kwarg=value 的方式來傳入實參。如:

student_info(score=100, age=19, name='ZhangSan', sex='malae')

不能在一次調用中多次對同一個參數進行賦值(即使多次賦值都是同一個值):

student_info('ZhangSan', 'male', name='ZhangSan')

這樣是不被允許的。

**name

當最后一個形參為**name 形式時,接收一個字典,該字典包含與函數中已定義形參之外的所有關鍵字參數。**name可以和*name形參組合使用(注意:*name必須在**name前面),*name接收一個元組,該元組包含形參列表之外的位置參數。

其中**name接收的字典中數據的順序和調用函數時實參傳入的順序一致。

3 特殊參數

默認情況下,參數可以按位置或顯式關鍵字傳遞給 Python 函數。為了讓代碼易讀、高效,最好限制參數的傳遞方式,這樣,開發者只需查看函數定義,即可確定參數項是僅按位置、按位置或關鍵字,還是僅按關鍵字傳遞。需要使用/*

函數定義如下:

def f(pos1, pos2, /, pos_or_kwd, *, kwd1, kwd2):
      -----------    -----------    ----------
           |              |             |
           |              |             |
        位置參數    位置參數或關鍵字參數  關鍵字參數

其中/* 是可選的。

3.1 位置或關鍵字參數

當函數定義中未使用/*時,參數可以按照位置或關鍵字傳遞給函數。

3.2 僅位置參數

特定形參可以標記為 僅限位置僅限位置 時,形參的順序很重要,且這些形參不能用關鍵字傳遞。僅限位置形參應放在 / (正斜杠)前。/ 用於在邏輯上分割僅限位置形參與其它形參。如果函數定義中沒有 /,則表示沒有僅限位置形參。

/ 后可以是 位置或關鍵字僅限關鍵字 形參。

3.3 僅限關鍵字參數

把形參標記為僅限關鍵字,表明必須以關鍵字參數的形式傳遞該參數。

3.4 函數示例

def standard_arg(arg):
  	print(arg)

def pos_only_arg(arg, /):
  	print(arg)

def kwd_only_arg(*, arg):
  	print(arg)
    
def combined_example(pos_only, /, standard, *, kwd_only):
  	print(pos_only, standard, kwd_only)

第一個函數 standard_arg 的函數定義對調用的方式沒有任何限制,可以按位置也可以按關鍵字傳遞參數:

standard_aeg(2)
standard_aeg(arg=2)

第二個函數 pos_only_arg 的函數定義中有 / ,且形參全在 / 之前定義,所以僅限使用位置參數。

pos_only_arg(3)
pos_only_arg(arg=3) # 無效的調用
# TypeError: pos_only_arg() got some positional-only arguments passed as keyword arguments: 'arg'

第三個函數 kwd_only_arg 的函數定義通過 * 表明僅限關鍵字參數。

kwd_only_arg(arg=5)
kwd_only_arg(5) # 無效的調用
# TypeError: kwd_only_arg() takes 0 positional arguments but 1 was given

最后一個函數 combined_example 的函數定義中,使用了全部三種調用慣例:

  • 該函數接收三個參數
  • 第一個參數僅限位置參數
  • 第二個參數可使用位置或關鍵字參數
  • 第三個參數僅限關鍵字參數
combined_example(6, 7, kwd_only=8)
combined_example(6, standard=7, kwd_only=8)

下面的函數定義中,kwds 里面不能把 name 當做鍵。會與第一個參數 name 沖突。

def foo(name, **kwds):
  	print(name, **kwds)
    
foo(1, **{name: 2})

因為上面的函數調用相當於把name 賦值了兩次。等價於:

foo(1, name=2)

由於此時name 既可以當作位置參數,也可以當作關鍵字參數,所以上述行為相當於給一個參數在一次函數調用中賦值了兩次。

那么如何才能讓 kwds 使用 name 當作鍵呢?

這就需要使用 特殊參數 / 來解決了,只要把 name 參數僅限使用位置參數,那么再使用name=2 時就不會被認為是第二次賦值了。

所以需要把函數定義為:

def foo(name, /, **kwds):
  	print(name, kwds)
    
foo(1, name=2, age=18)
# 1 {'name': 2, 'age': 18}

就可以了。👼

總結:僅限位置形參的名稱可以在**kwds中使用,而不產生歧義。

4 任意實參列表

調用函數時,使用任意數量的實參是最少見的選項。這些實參包含在元組中。

有時候,需要接受任意數量的實參,但預先不知道傳遞給函數的會是什么樣的信息。在這種 情況下,可將函數編寫成能夠接受任意數量的鍵值對——調用語句提供了多少就接受多少。

def sumnum(a, *ddd):
    print(a)
    result = a
    for num in ddd:
        result += num
    return result
print(sumnum(1, 2, 3, 5, 6, 9, 8, 7))
# 1
# 41

*name 用於接收傳遞給函數的所有剩余位置參數,因此*name 的后面不允許出現位置參數,而是僅限關鍵字參數,同樣的*name 的前面也不允許出現任何的關鍵字參數,而是僅限位置參數。

5 解包實參列表

函數調用要求獨立的位置參數,但實參在列表或元組里時,要執行相反的操作。例如,內置的 range() 函數要求獨立的 start 和 stop 實參。如果這些參數不是獨立的,則要在調用函數時,用 * 操作符把實參從列表或元組解包出來:

>>> list(range(3, 6))         
[3, 4, 5]
>>> args = [3, 6]
>>> list(range(*args))         
[3, 4, 5]

同樣,字典可以用 ** 操作符傳遞關鍵字參數。

6 Lambda 表達式

Lambda 關鍵字用於創建小巧的匿名函數。

Lambda a, b: a+b

上面的函數返回兩個參數的和。Lambda 函數可用於任何需要函數對象的地方。在語法上,匿名函數只能是單個表達式。在語義上,它只是常規函數定義的語法糖。與嵌套函數定義一樣,lambda 函數可以引用包含作用域中的變量:

def make_incrementor(n):
    return lambda x: x + n

f = make_incrementor(42)
print(f(0))
# 42
print(f(1))
# 43

上例用 lambda 表達式返回函數。還可以把匿名函數用作傳遞的實參:

pairs = [(1, 'one'), (2, 'two'), (3, 'three'), (4, 'four')]
pairs.sort(key=lambda pa: pa[1])
print(pairs)
# [(4, 'four'), (1, 'one'), (3, 'three'), (2, 'two')]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM