装饰方法(类方法重载)

Kir*_*rov 4 python methods decorator python-3.x

受Muhammad Alkarouri的启发,回答Python3的"功能注释"有什么用处,我想multimethod为方法做到这一点,而不是常规功能.但是,当我这样做

registry = {}

class MultiMethod(object):
    def __init__(self, name):
        self.name = name
        self.typemap = {}
    def __call__(self, *args):
        types = tuple(arg.__class__ for arg in args) # a generator expression!
        function = self.typemap.get(types)
    if function is None:
        raise TypeError("no match")
    return function(*args)
def register(self, types, function):
    if types in self.typemap:
        raise TypeError("duplicate registration")
    self.typemap[types] = function

def multimethod(function):
    name = function.__name__
    mm = registry.get(name)
    if mm is None:
        mm = registry[name] = MultiMethod(name)
    types = tuple(function.__annotations__.values())
    mm.register(types, function)
    return mm

class A:
@multimethod
def foo(self, a: int):
    return "an int"

a = A() 
print( a.foo( 1 ) ) 
Run Code Online (Sandbox Code Playgroud)

我懂了:

Traceback (most recent call last):
  File "test.py", line 33, in <module>
    print( a.foo( 1 ) )
  File "test.py", line 12, in __call__
    return function(*args)
TypeError: foo() takes exactly 2 arguments (1 given)
Run Code Online (Sandbox Code Playgroud)

正如装饰方法中所解释的那样,这似乎是预期的,因为这个self论点.

但我不知道如何让它发挥作用.好吧,当我删除"自我"时,它工作(几乎)很好,但我不想删除它.请注意,我正在练习这个,我知道有一些libs,提供方法重载.

我尝试了什么:

  • 很无聊的,但想尝试-添加的参数selfdef multimethod( function )-同样的错误

  • 我想到了将在__init__class MultiMethod第三个参数- obj并存储self为成员,但我不能这样过multimethod,因为它是一个函数.

  • 我不想为装饰器添加参数,因此忽略了这些选项(如果可能的话)

我读了几个类似的问题,但没找到我要找的东西.我很确定这是一个虚假的问题,但我没有想法.

Joc*_*zel 5

您遇到的基本问题是您使用类来代替函数.没有机制将该类绑定到它调用的实例,这与自动发生的函数不同.

简而言之,当你这样做a.foo( .. )时返回一个MultiMethod,但是这个对象不知道它应该被绑定a.

您必须以某种方式传递实例.一种简单的方法是将它全部包装在一个函数中,让Python做到这一点:

registry = {}

class MultiMethod(object):
    def __init__(self, name):
        self.name = name
        self.typemap = {}

    # self = a MultiMethod instance, instance = the object we want to bind to
    def __call__(self, instance, *args):
        types = tuple(arg.__class__ for arg in args) # a generator expression!
        function = self.typemap.get(types)

        if function is None:
            raise TypeError("no match")
        return function(instance, *args)

    def register(self, types, function):
        if types in self.typemap:
            raise TypeError("duplicate registration")
        self.typemap[types] = function

def multimethod(function):
    name = function.__name__
    mm = registry.get(name)
    if mm is None:
        mm = registry[name] = MultiMethod(name)

    types = tuple(function.__annotations__.values())
    mm.register(types, function)
    # return a function instead of a object - Python binds this automatically
    def getter(instance, *args, **kwargs):
        return mm(instance, *args, **kwargs)
    return getter

class A:
    @multimethod
    def foo(self, a: int):
        return "an int", a

a = A() 
print( a.foo( 1 ) )
Run Code Online (Sandbox Code Playgroud)

更复杂的方法是在A执行此绑定的类上编写自己的描述符.