【问题标题】:Decorating class methods to call a method from the same name装饰类方法以调用同名方法
【发布时间】:2021-12-29 09:13:58
【问题描述】:

我有一个类有一堆看起来相似的方法,例如:

class Foo(object):
    def __init__(self, delegate= None):
        self.delegate = delegate
    
    def some_method(self):
        if self.delegate:
            return self.delegate.some_method()

        return "this is some other value"

我的想法是这样的包装器:

def use_delegate(fun):
    def wrap(self, *args):
        if self.delegate:
             return fun(self.delegate, *args)
        return fun(self, *args)

    return wrap

class Foo(object):
    def __init__(self, delegate= None):
        self.delegate = delegate

    @use_delegate
    def some_method(self):
        return "this is some other value"
    

问题来了:如果“self.delegate”是Foo的子类,则调用了错误的方法:

    class Bar(Foo):
        def some_method(self):
            return "This is the output I want"

    >>> bar = Bar()
    >>> bar.some_method()
 'This is the output I want'
    >>> foo= Foo(bar)
    >>> foo.some_method()
 'this is some other value'

到目前为止,我发现这是可行的,但它看起来真的很丑:

def use_delegate(fun):
    def w(self, *args):
        if self.delegate:
            return self.delegate.__getattribute__(fun.__name__)(*args)

        return fun(self, *args)

    return w

我想知道是否有更好的方法来完成同样的事情。

【问题讨论】:

  • 为什么要包装实例delegate而不是直接使用呢?这看起来像是一个设计问题。
  • 确实,我怀疑我的设计很糟糕,我必须考虑一下,但我仍然认为它是一个很好的编程难题。

标签: python oop python-decorators


【解决方案1】:

首先,我尝试了您的(原始)装饰器,但没有 Bar 是 Foo 的子类,但它对我不起作用。这是合乎逻辑的,因为在您的第一个包装器中,您调用 fun,它是 Foo 的函数 some_method。你可以在调试器中看到:

function Foo.some_method at 0x...

我实际上有点惊讶它可以工作,但它又是 python(你甚至可以用字符串或 int 或 wathever 替换 self.delegate,它仍然可以工作)。

现在进入下一个装饰器方式。如果您想保留装饰器,我认为您所写的内容没有更好的解决方案。所以,我能找到的唯一小改进是:

def use_delegate(fun):
    def w(self, *args):
        if self.delegate:
            assert hasattr(self.delegate, fun.__name__) # here
            return getattr(self.delegate, fun.__name__)(*args) # and here

        return fun(self, *args)

    return w

【讨论】:

  • 此时只是好奇,但您将如何以不同于装饰者的方式解决问题?
  • 我会像你第一次那样做。 return self.delegate.some_func if self.delegate else "..." 。其他任何事情似乎都遥不可及。但正如 chepner 所说,这看起来像是一个设计问题。
猜你喜欢
  • 1970-01-01
  • 2014-01-14
  • 2020-01-11
  • 1970-01-01
  • 2019-12-20
  • 2011-07-01
  • 2011-08-25
  • 2021-10-23
  • 2019-11-16
相关资源
最近更新 更多