装饰方法(类方法重载)

发布于 2024-11-07 20:20:35 字数 2000 浏览 0 评论 0原文

受到 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 ) ) 

我得到了这个:

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)

这似乎是预期的,如装饰方法中所述,因为 self 参数。

但我不知道如何让它发挥作用。好吧,当我删除“自我”时,它工作(几乎)正常,但我不想删除它。请注意,我这样做是为了练习,我知道有一些库提供方法重载。

我尝试过的:

  • 非常愚蠢,但想尝试 - 在 def multimethod( function ) 中添加参数 self - 相同的错误

  • 我考虑添加 __init__ 的 < code>class MultiMethod 第三个参数 - obj 并将 self 存储为成员,但我无法通过 multimethod 执行此操作,因为它是一个函数。

  • 我不想为装饰器添加参数,所以这个选项(如果可能的话)被忽略

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

Inspired by Muhammad Alkarouri answer in What are good uses for Python3's "Function Annotations" , I want to do this multimethod for methods, not regular functions. However, when I do this

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 ) ) 

I got this:

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)

Which seems to be expected, as explained in Decorating a method , because of the self argument.

But I have no idea how to make it work. Well, when I remove the "self", it's working (almost) fine, but I don't want to remove it. Please note, that I'm doing this for practice, I know that there are some libs, providing method overloading.

What I tried:

  • very silly, but wanted to try - added parameter self in def multimethod( function ) - the same error

  • I thought about adding in the __init__ of class MultiMethod a third parameter - obj and stored self as member, but I can't do this through multimethod as it is a function.

  • I don't want to add parameters for the decorator, so this options (if possible at all) is ignored

I read several similar questions, but didn't find what I was looking for. I'm pretty sure this is dummy question, but I ran out of ideas.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

别闹i 2024-11-14 20:20:35

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

简而言之,当您执行 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 ) )

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

The basic problem you have is that you use a class in place of a function. There is no mechanism to bind that class to the instance it's called from, unlike a function where this happens automatically.

In short, when you do a.foo( .. ) it returns a MultiMethod, but this object has no idea that it is supposed to be bound to a.

You have to pass in the instance in some way or another. One easy way is to wrap it all in a function and let Python do it's thing:

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 ) )

The more complex way would be to write your own descriptor on the A class that does this binding.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文