声明:本内容非盈利性质,也不支持任何组织或个人将其用作盈利用途。本内容来源于参考书或网站,会尽量附上原文链接,并鼓励大家看原文。侵删。

5.2.5 装饰器使用案例-自定义装饰器实现方法重载

python中提供了@singledispatchmethod装饰器实现了单分派的泛型函数(函数重载)。如下:

class Negator:
@singledispatchmethod
def neg(self, arg):
    raise NotImplementedError("Cannot negate a")

@neg.register
def _(self, arg: int):
    return -arg

@neg.register
def _(self, arg: bool):
    return not arg

但@singledispatchmethod是根据函数参数列表的第一个参数类型不同来确定走哪个重载分支的。但在对于类中的方法,其第一个参数都是self或cls,因此这个装饰器不能再使用了。当python版本小于3.8时,没有提供其他的支持泛型函数的装饰器。@singledispatchmethod装饰器内层函数原码如下:

def wrapper(*args, **kw):
    return dispatch(args[0].__class__)(*args, **kw)

# 可以看到取的是第一个参数

当python版本小于3.8时,我们想要实现类中的泛型函数,需要重写@singledispatchmethod的wrapper函数,将args[0]修改为args[1]。代码如下:

from functools import singledispatch, update_wrapper

# 借助@singledispatchmethod的wrapper重新定义一个装饰器
def methdispatch(func):
    dispatcher = singledispatch(func)
    def wrapper(*args, **kw):
        return dispatcher.dispatch(args[1].__class__)(*args, **kw)
    wrapper.register = dispatcher.register
    update_wrapper(wrapper, func)
    return wrapper


# 测试使用装饰器
class Negator:
@methdispatch
def neg(self, arg):
    raise NotImplementedError("Cannot negate a")

@neg.register
def _(self, arg: int):
    return -arg

@neg.register
def _(self, arg: bool):
    return not arg

if __name__ == '__main__':
neg = Negator()
neg.neg(1)
neg.neg(False)
11-20 07:47