函数重载是指允许定义参数数量或类型不同的同名函数,程序在运行时会根据所传递的参数类型选择应该调用的函数 ,但在默认情况下,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)来实现重载
所以,单分派泛型函数就是根据函数的第一个参数类型决定使用哪个函数的泛型函数
将一个函数声明为泛型函数可以使用修饰器@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 - 3 Foo([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属性
python默认不支持重载,但可以使用单分派泛型函数实现,声明泛型函数需要使用修饰器@singledispatch,它有三个属性,register用来注册针对特定类型的“重载函数”,这里必须指明针对的是哪一个特定的类型,可以给第一个参数类型注释,也可以给register传入一个显式类型,否则会抛出TypeError异常;dispatch属性用来查看特定的类型将要选择的函数;registry用来访问所有已注册的实现。
参考链接:
functools.singledispatch
single dispatch
generic function
python中的重载
为什么 Python 不支持函数重载?其他函数大部分都支持的?
