这是 mm.py 中代码
编辑日期: 2024-11-28 文章阅读: 次
参考Python创建者龟叔在2005年写的一篇博文,是关于Python函数重载的话题,从龟叔的几十行代码中就能看出他的非凡智慧,我有幸在上面做出一些修改。 我们知道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
对象
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
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):
print(f"a={a}, b={b}")
@multimethod(float, float)
def foo(a, b):
print(f"a={a}, b={b}")
@multimethod(str, str)
def foo(a, b):
print(f"a={a}, b={b}")
最后foo
就可以实现函数重载了,调用它们:
foo(2,1)
foo(2.0, 1.0)
foo('2.0s', '1.0s')
函数名=foo, 参数类型=(<class 'int'>, <class 'int'>)
a=2, b=1
函数名=foo, 参数类型=(<class 'float'>, <class 'float'>)
a=2.0, b=1.0
函数名=foo, 参数类型=(<class 'str'>, <class 'str'>)
a=2.0s, b=1.0s
参考龟书的这篇博文: https://www.artima.com/weblogs/viewpost.jsp?thread=101605