以下代码适用于python3,但不适用于python2。为了清楚起见,我尝试将另一个类(Class1)中的成员函数注入/猴子修补到目标类(Class2)中,以便该函数使用self中的适当成员属性。
为什么它在python3中可以工作,我还可以做些什么来在python2中获得所需的行为?
class Parent:
def foo(self):
print("foo of class Parent: instance " + self.__class__.__name__)
def __init__(self):
self.d = {"foo": self.__class__.foo}
def bar(self):
self.d['foo'](self)
self.d['foo'] = Child1.foo
self.d['foo'](self)
class Child1(Parent):
def foo(self):
print("foo of class Child1: instance " + self.__class__.__name__)
class Child2(Parent):
pass
Child2().bar()
答案 0 :(得分:2)
您要在此处执行的操作是使用非Child2.foo
的{{1}}调用未绑定方法self
。
这是非法的,Python 2将检测到该错误并提出一个Child2
来解释到底是什么问题:
TypeError
在Python 3中,没有未绑定的方法对象。未绑定的方法只是普通的旧函数。因此,他们无法检查您是否试图做任何非法的事情。然后,由于实际上并没有使用TypeError: unbound method foo() must be called with Child1 instance as first argument (got Child2 instance instead)
方法内部的self
是Child2
的事实,因此您无需理会。 p>
但是您不能以这种方式注入实际使用foo
的{{1}}形式的方法。他们最终只会引发Child2
或Child2
或调用错误的方法。它仅适用于没有理由成为方法的方法。
如果您仍然确实希望在Python 2中实现此行为,则可以通过从未绑定方法中提取函数来获得它:
TypeError
(如果您想使用更早的2.x版本,请在此处使用AttributeError
而不是 self.d['foo'] = Child1.foo.__func__
。)
现在,它根本不是一种方法,并且,如果您尝试通过描述符协议将其实际绑定到im_func
或通过构造__func__
来绑定,则会得到相同的旧{{ 1}}。但这是一个函数,您可以使用任何需要作为函数的参数来调用它。而且,由于您的函数对需要self
的{{1}}参数不执行任何操作,因此它将起作用。
我们正在讨论,您几乎可以肯定希望MethodType
在这里成为一种新型的类。而且,您可能想在Python 2和Python 3中使用相同的代码,而不要对两者的行为都使用不同的代码。所以:
TypeError