假设你有一个函数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}')
复制代码
同时,还有一个须要注意的点,就是只有第一个参数的不一样类型会被重载。后面的参数的类型变化会被自动忽略。