注入一个python类成员函数

问题描述 投票:1回答:1

以下代码适用于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()
python functional-programming
1个回答
2
投票

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

这是非法的,Python 2将检测到并提出一个TypeError,它解释了什么是错误的:

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

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


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


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

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

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

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


虽然我们在这里,你几乎肯定希望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()
© www.soinside.com 2019 - 2024. All rights reserved.