装饰方法(类方法重载) [英] Decorating method (class methods overloading)

查看:61
本文介绍了装饰方法(类方法重载)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

受Muhammad Alkarouri的启发,其答案在 Python3的良好用法是什么? ; Function Annotations" ,我想对方法(而不是常规函数)执行此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 ) ) 

我知道了:

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,如装饰方法所述,这似乎是预期的.论点.

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.

我尝试过的事情:

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

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

我考虑过要在class MultiMethod__init__中添加第三个参数-obj并将self存储为成员,但是我无法通过multimethod进行此操作,因为它是一个函数.

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.

推荐答案

您遇到的基本问题是,您使用类代替了函数.没有将该类绑定到从其调用的实例的机制,这与自动执行该功能的函数不同.

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.

简而言之,当您执行a.foo( .. )时,它会返回MultiMethod,但是此对象不知道应该绑定到a.

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.

您必须以某种方式传递实例.一种简单的方法是将所有内容包装在一个函数中,然后由Python完成:

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

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

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

这篇关于装饰方法(类方法重载)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆