DAY 11. python 重載
函數重載是指允許定義參數數量或類型不同的同名函數,程序在運行時會根據所傳遞的參數類型選擇應該調用的函數
,但在默認情況下,python是不支持函數重載的,定義同名函數會發生覆蓋
def foo(a:int):print(f'int {a}')def foo(b:list):print(f'list{b}')foo(3)
foo([i for i in range(3)])# list3
# list[0, 1, 2]
至于不支持的原因,我想大概是沒必要,首先,只在兩種情況下可能發生函數重載,一是參數類型不同,二是參數個數不同,對于第一種情況,鴨子類型的存在使得函數不在乎參數類型而只關心參數的行為,所以你可以傳遞任何類型的參數,對于第二種情況,缺省參數的使用使得可以傳遞任意多個參數,因此函數的重載在python中就顯得很雞肋了,但如果非要實現函數重載,可以使用3.4中增加的轉發機制即單分派泛型函數(single-dispatch generic function)來實現重載
11.2 單分派泛型函數
- 泛型函數 generic function :由多個函數組成的函數,可以根據不同的參數類型決定調用那個函數
- 單分派,single-dispatch:一種泛型函數分派形式,其中實現是根據單個參數的類型選擇的。
所以,單分派泛型函數就是根據函數的第一個參數類型決定使用哪個函數的泛型函數
將一個函數聲明為泛型函數可以使用修飾器@singledispatch
,需要從functools
模塊導入,singledispatch有兩個常用方法,register和dispatch
from functools import singledispatch@singledispatch
def Foo(arg,*args):print(arg)
這樣就實現了一個泛型函數,他的分派發生在第一個參數類型上,如果想要基于此實現重載,需要使用他的register方法,
from functools import singledispatch@singledispatch
def Foo(arg,*args):print(arg)# 使用了類型注釋
@Foo.register
def _1(arg:int,*args):print(f'int - {arg}')# 沒有使用類型注釋,顯式傳遞給修飾器
@Foo.register(list)
def _2(arg,*args):print(f'list - {arg}')if __name__ == '__main__':Foo(3) # int - 3Foo([i for i in range(10)]) # list - [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
對于使用了類型注釋的變量,singledispatch會自動推斷第一個參數的類型,如上面int的那個,對于沒有使用類型注釋的變量,可以顯式傳遞類型給singledispatch,如下面list的那個
register屬性還可以以函數的形式調用,這可以用在lambdas表達式上,如
>>> def nothing(arg, verbose=False):
... print("Nothing.")
...
>>> fun.register(type(None), nothing)
如果沒有實現針對特定類型的注冊,那么就會使用被@singledispatch修飾的函數
Foo("string") # string
要檢查泛型函數將為給定類型選擇哪個實現,請使用dispatch()屬性
print(Foo.dispatch(int)) # <function _1 at 0x000001D7C2724B70>
print(Foo.dispatch(list)) # <function _2 at 0x000001D7C2792E18>
print(Foo.dispatch(str)) # <function Foo at 0x000001FB456FC268>
要訪問所有已注冊的實現,請使用只讀的registry屬性
11.3 總結
python默認不支持重載,但可以使用單分派泛型函數實現,聲明泛型函數需要使用修飾器@singledispatch,它有三個屬性,register用來注冊針對特定類型的“重載函數”,這里必須指明針對的是哪一個特定的類型,可以給第一個參數類型注釋,也可以給register傳入一個顯式類型,否則會拋出TypeError異常;dispatch屬性用來查看特定的類型將要選擇的函數;registry用來訪問所有已注冊的實現。
參考鏈接:
functools.singledispatch
single dispatch
generic function
python中的重載
為什么 Python 不支持函數重載?其他函數大部分都支持的?