假設你有一個函數connect,它有一個參數address,這個參數多是一個字符串,也多是一個元組。例如:python
connect('123.45.32.18:8080')
connect(('123.45.32.18', 8080))
複製代碼
你想在代碼裏面兼容這兩種寫法,因而你可能會這樣寫代碼:函數
def connect(address):
if isinstance(address, str):
ip, port = address.split(':')
elif isinstance(address, tuple):
ip, port = address
else:
print('地址格式不正確')
複製代碼
這種寫法簡單直接,可是若是參數的類型更多,那麼你就須要寫很長的 if-elif-elif-...-else
。代碼看起來就很是不美觀。學習
學習過 Java 的同窗,應該對函數重載比較熟悉,能夠定義幾個名字相同的函數,可是他們的參數類型或者數量不一樣,從而實現不一樣的代碼邏輯。spa
在 Python 裏面,參數的數量不一樣可使用默認參數來解決,不須要定義多個函數。那若是參數類型不一樣就實現不一樣的邏輯,除了上面的 if-else
外,咱們還可使用functools
模塊裏面的singledispatch
裝飾器實現函數重載。code
咱們來寫一段代碼:cdn
from functools import singledispatch
@singledispatch
def connect(address):
print(f' 傳輸參數類型爲:{type(address)},不是有效類型')
@connect.register
def _(address: str):
ip, port = address.split(':')
print(f'參數爲字符串,IP是:{ip}, 端口是:{port}')
@connect.register
def _(address: tuple):
ip, port = address
print(f'參數爲元組,IP是:{ip}, 端口是:{port}')
connect('123.45.32.18:8080')
connect(('123.45.32.18', 8080))
connect(123)
複製代碼
咱們運行一下這段代碼,你們看看根據參數的不一樣,有什麼樣的不一樣效果:blog
能夠看到,咱們調用的函數,始終都是connect
,可是因爲傳入參數的類型不一樣,它運行的結果也不同。ip
咱們使用singledispatch
裝飾一個函數,那麼這個函數就是咱們將會調用的函數。字符串
這個函數在傳入參數不一樣時的具體實現,經過下面註冊的函數來實現。註冊的時候使用@咱們定義的函數名.register
來註冊。被註冊的函數名叫什麼可有可無,因此這裏我都直接使用下劃線代替。string
被註冊的函數的第一個參數,經過類型標註來肯定它應該使用什麼類型。當咱們調用咱們定義的函數是,若是參數類型符合某個被註冊的函數,那麼就會執行這個被註冊的函數。若是參數類型不知足任何一個被註冊的函數,那麼就會執行咱們的原函數。
使用類型標註來指定參數類型是從 Python 3.7才引入的新特性。在 Python 3.6或以前的版本,咱們須要經過@咱們定義的函數名.register(類型)
來指定類型,例如:
from functools import singledispatch
@singledispatch
def connect(address):
print(f' 傳輸參數類型爲:{type(address)},不是有效類型')
@connect.register(str)
def _(address):
ip, port = address.split(':')
print(f'參數爲字符串,IP是:{ip}, 端口是:{port}')
@connect.register(tuple)
def _(address):
ip, port = address
print(f'參數爲元組,IP是:{ip}, 端口是:{port}')
複製代碼
同時,還有一個須要注意的點,就是隻有第一個參數的不一樣類型會被重載。後面的參數的類型變化會被自動忽略。