你好,我是zhenguo
我们知道Python语法本身并不支持函数重载 ,龟叔2005年写的一篇博文中说到:函数重载太高级了以至于他不会用到。但是龟叔不愧是仁慈大叔,他依然给出了Python实现函数重载的方法,代码实现在我看来简洁高级又明确。
因为不支持函数重载,所以下面两个f的定义,第二个会覆盖第一个,因此调用第一个会报错:第一个
def f (a: int) : print(f'a={a} ' )
第二个
def f (a: int, b: float) : print(f'a={a} , b' )
调用第一个:
f(1 )
打印:
TypeError: f() missing 1 required positional argument: 'b'
龟叔使用装饰器对待重载的函数进行增强,使用registry
作为函数字典,函数名为键,值为封装的MultiMethod
对象
# 这是 mm.py 中代码 # 这是函数重载装饰器multimethod def multimethod (*types) : def register (f) : f_name = f.__name__ mm = registry.get(f_name) if mm is None : mm = registry[f_name] = MultiMethod(f_name) mm.register(types, f) return mm return register
MultiMethod
内部封装的type_dict
属性是同一个函数名下的不同版本字典,注意只支持位置参数 ,使用参数组合类型作为key,其值为对应函数f
# 这是 mm.py 中代码 # 模块级变量 registry = {} # 函数注册字典 class MultiMethod (object) : def __init__ (self, f_name) : self.f_name = f_name self.type_dict = {} def __call__ (self, *args) : types = tuple(type(arg) for arg in
args) # 生成器表达式 print(f"函数名={self.f_name} , 参数类型={types} " ) function = self.type_dict.get(types) if function is None : raise TypeError(f"{types} 不支持" ) return function(*args) def register (self, types, function) : if types not in self.type_dict: self.type_dict[types] = function
这样后multimethod
装饰器就具备函数重载功能,以下foo
分别重载2个int,2个float,2个str
@multimethod(int, int) def foo (a, b) : # 对整型a和b处理 print(f"a={a} , b={b} " )@multimethod(float, float) def foo (a, b) : # 对浮点型a和b处理 print(f"a={a} , b={b} " )@multimethod(str, str) def foo (a, b) : # 对字符串a和b处理 print(f"a={a} , b={b} " )
最后foo
就可以实现函数重载了,调用它们:
foo(2 ,1 ) foo(2.0 , 1.0 ) foo('2.0s' , '1.0s' )
打印结果如下所示:
函数名=foo, 参数类型=('int'>, 'int'>) a=2, b=1 函数名=foo, 参数类型=('float'>, 'float'>) a=2.0, b=1.0 函数名=foo, 参数类型=('str'>, 'str'>) a=2.0s, b=1.0s
参考龟叔的这篇博文:https://www.artima.com/weblogs/viewpost.jsp?thread=101605
--- EOF ---