代码之家  ›  专栏  ›  技术社区  ›  Matias Cicero

无法覆盖\调用的实现__

  •  2
  • Matias Cicero  · 技术社区  · 7 年前

    以这个为例:

    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'
    

    我可以复制这两个 巨蟒2.x 蟒蛇3.x

    我找不到有关这一行为的文档的任何相关信息。

    这对我来说完全是一个有效的用例,特别是在MonkeyPatching的时候。

    这是不允许的原因吗?

    3 回复  |  直到 7 年前
        1
  •  2
  •   khelwood Muhammed Elsayed.radwan    7 年前

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

    Foo.__call__ = lambda _: 'bye'
    print(foo()) # prints 'bye'
    
        2
  •  1
  •   Kewl ErinPac    7 年前

    试试这个:

    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
  •  1
  •   jedwards    7 年前

    通常,您可以这样做。重写单个实例对给定方法的实现,而不影响其余方法。

    这里的问题是,您正试图重写一个“特殊”方法。这个 () 调用语法查找 __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)
    

    但我更喜欢明确的定义。