【问题标题】:Cannot overwrite implementation for __call__无法覆盖 __call__ 的实现
【发布时间】:2018-06-12 12:17:10
【问题描述】:

以此为例:

class Foo(object):
   def __init__(self, msg):
      self._msg = msg
   def __call__(self):
      return self._msg

foo = Foo('hello')
print(foo()) # Prints 'hello'
foo.__call__ = lambda _: 'bye'
print(foo()) # Prints 'hello'

我可以在 Python 2.xPython 3.x

上重现这一点

我无法在有关此行为的文档中找到任何相关信息。

这对我来说完全是一个有效的用例,特别是在猴子补丁时。

这是不允许的原因吗?

【问题讨论】:

标签: python


【解决方案1】:

当您使用() 调用对象时,它会执行对象类型上定义的__call__ 方法。所以__call__ 是在类Foo 上定义的,而不是在你的实例foo 上。如果您重新分配Foo.__call__,它会起作用。

Foo.__call__ = lambda _: 'bye'
print(foo()) # prints 'bye'

【讨论】:

  • 我不确定您所说的“实例方法”是什么意思,但这里的关键问题是它是一种“特殊”(dunder)方法,() 在类上查找__call__ .您当然可以覆盖单个实例对“常规”方法的实现。
【解决方案2】:

试试这个:

class Foo(object):
    def __init__(self, msg):
        self._msg = msg
    def __call__(self):
        return self._msg

foo = Foo('hello')
print(foo()) # Prints 'hello'

Foo.__call__ = lambda _: 'bye' #Notice the capital F, this is the class not the instance
print(foo()) # Prints 'bye'

最后一次通话应该像您期望的那样打印“再见”。当你调用一个实例的函数时,它实际上是指类函数(它们被定义的地方)

【讨论】:

    【解决方案3】:

    通常,您可以这样做。覆盖给定方法的单个实例的实现,而不影响其余部分。

    这里的问题是您试图覆盖“特殊”方法。 () 调用语法在类而不是实例上查找 __call__ 方法。

    以下代码显示您可以覆盖单个实例的方法实现,并作为一种丑陋的解决方法来解决您的问题:

    class Foo(object):
        def __init__(self, msg):
            self._msg = msg
        def __call__(self):
            return self.call()      # Delegate call to instance
        def call(self):
            return self._msg
    
    foo = Foo('hello')
    other = Foo('hi')
    
    print(foo()) # Prints 'hello'
    
    def new_call(self):
        return "bye"
    
    foo.call = new_call.__get__(foo, Foo)
    print(foo()) # Prints 'bye'
    
    print(other()) # Prints 'hi' (unaffected by override)
    

    注意:以下内容也可以按您的预期工作:

    foo.call = (lambda _: "bye").__get__(foo, Foo)
    

    但我更喜欢明确的定义。

    【讨论】:

      猜你喜欢
      • 2016-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-07
      • 2012-09-16
      相关资源
      最近更新 更多