注入一个python类成员函数

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (1)
  • 关注 (0)
  • 查看 (144)

以下代码适用于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()
提问于
用户回答回答于

你在这里要做的是Child2.fooself不是a的方法调用未绑定的方法Child2

这是非法的,Python 2将检测到并提出一个TypeError解释错误的地方:

TypeError: unbound method foo() must be called with Child1 instance as first argument (got Child2 instance instead)

在Python 3中,没有未绑定的方法对象; 未绑定的方法只是普通的旧函数。因此,他们无法检查您是否正在尝试做任何违法行为。然后,因为你实际上并没有使用方法内部的事实,self所以你可以逃脱它。Child2foo

但你不能注入实际使用的方法Child2的-ness Child2这种方式; 他们最终会提出一个TypeError或者说AttributeError错误的方法。它只适用于首先没有理由成为方法的方法。

如果你真的想在Python 2中使用这种行为,你可以通过从未绑定方法中提取函数来获得它:

    self.d['foo'] = Child1.foo.__func__

(如果你想使用更老的2.x,请使用im_func而不是__func__那里。)

现在,它根本不是一种方法 - 如果你试图将它实际上与self描述符协议绑定或者通过构建一个方法MethodType,你就会得到相同的旧方法TypeError。但它是一个函数,你可以用你想要的任何参数作为函数来调用它。而且,因为你的函数对self那个要求它的参数没有任何作用Child2,所以它会起作用。

虽然我们在这里,你几乎肯定想Parent在这里成为一个新式的课程。您可能希望在Python 2和Python 3中使用相同的代码,而不是在两者中使用相同行为的不同代码。所以:

class Parent(object): # makes it a new-style class in 2.x as well as 3.x
  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)
    # Gets __func__ if it's an unbound method (2.x), leaves it alone if not (3.x)
    self.d['foo'] = getattr(Child1.foo, '__func__', 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()

扫码关注云+社区

领取腾讯云代金券