【问题标题】:How to monkeypatch one class's instance method to another one?如何将一个类实例方法monkeypatch到另一个?
【发布时间】:2013-09-10 07:36:33
【问题描述】:

给定一个类A,我可以简单地通过添加一个实例方法a

def a(self):
    pass

A.a = a

但是,如果我尝试添加另一个类B 的实例方法b,即A.b = B.b,则尝试调用A().b() 会产生一个

TypeError: 未绑定的方法b() 必须以B 实例作为第一个参数调用(什么都没有)

(虽然B().b() 很好)。确实有区别

A.a -> <unbound method A.a>
A.b -> <unbound method B.b>  # should be A.b, not B.b

所以,

  • 如何解决这个问题?
  • 为什么会这样?这似乎并不直观,但通常 Guido 有一些很好的理由......

奇怪的是,这在 Python3 中不再失败...

【问题讨论】:

标签: python python-2.x monkeypatching instance-methods


【解决方案1】:

让我们:

class A(object): pass

class B(object):
    def b(self): 
        print 'self class: ' + self.__class__.__name__

当你在做的时候:

A.b = B.b

您不是将函数附加到A,而是未绑定的方法。因此,python 仅将其添加为标准属性,而不会将其转换为 A-unbounded 方法。解决方法很简单,附上底层函数:

A.b = B.b.__func__

print A.b
    # print: <unbound method A.b>
a = A()
a.b()
    # print: self class: A

我不知道未绑定方法和函数之间的所有区别(仅第一个包含第二个),也不知道所有这些在内部如何工作。所以我无法解释它的原因。我的理解是,一个方法对象(绑定与否)比函数需要更多的信息和功能,但它需要一个来执行。

我同意自动执行此操作(更改未绑定方法的类)可能是一个不错的选择,但我可以找到不这样做的理由。因此,python 3 与 python 2 的不同令人惊讶。我想找出这个选择的原因。

【讨论】:

  • 谢谢,我担心那会更复杂!
【解决方案2】:

当您引用类实例上的方法时,该方法将绑定到该类实例。

B().b 等价于:lambda *args, **kwargs: b(&lt;B instance&gt;, *args, **kwargs)

我怀疑您在评估 B.b. 时得到了类似(但不完全相同)的包装参考。然而,这不是我所期望的行为。

有趣的是:

A.a = lambda s: B.b(s)
A().a()

产量:

TypeError: 未绑定的方法 b() 必须首先以 B 实例调用 参数(取而代之的是 A 实例)

这表明B.b 正在评估实际方法的包装器,并且包装器正在检查“self”是否具有预期的类型。我不知道,但这可能与解释器的效率有关。

不过,这是一个有趣的问题。希望有人能给出更明确的答案。

【讨论】:

  • 奇怪的是,在 Python3 上一切正常,其中(参见答案here)这个令人困惑的未绑定方法概念已被放弃
  • 嗯,正如Juh_ 所示,只需使用B.b.__func__。仍然是一个奇怪的“功能”,难怪它不再在 Python3 中......
猜你喜欢
  • 2011-07-03
  • 2021-09-17
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-18
  • 2014-11-05
  • 1970-01-01
  • 2013-09-19
相关资源
最近更新 更多