是否可以从另一个类的方法执行动态方法覆盖?如果是这样,怎么样?

时间:2018-01-11 15:45:33

标签: python dynamic method-overriding

我查看了以下帖子和博客,其中解释了使用函数执行此操作。我想知道它是否合法为类或对象方法做同样的事情? 将会欣赏适用于Python2的答案(尽管很好地了解它对Python3的作用)。

来自stackoverflow的来源:

Override module method where from...import is usedOverride a method at instance level

内容相似的博客:

https://tryolabs.com/blog/2013/07/05/run-time-method-patching-python/ http://igorsobreira.com/2011/02/06/adding-methods-dynamically-in-python.html

这段代码说明了我的意图以及我的尝试:

class Person:
        def __init__(self, name):
            self.name = name


    class OtherPerson:
        def __init__(self, name):
            self.name = name 

        def do_something(self):
            print self.name + '$$'

  p = Person('alpha')
  p.do_something = OtherPerson.do_something
  # TypeError: unbound method do_something() must be called with 
  OtherPerson #instance as first argument (got nothing instead)
  p.do_something()
  op = OtherPerson('beta')
  p.do_something = op.do_something

  # output: 'beta$$' I would like to get 'alpha$$'
  p.do_something()

尝试了以下来自@khelwood的建议:

Person.do_something = OtherPerson.do_something
#TypeError: unbound method do_something() must be called with OtherPerson instance as first argument (got nothing instead)
# Works if OtherPerson.do_something is staticmethod
p.do_something()

2 个答案:

答案 0 :(得分:0)

如果OtherPerson.do_something是staticmethod:

,则可以这样做
class Person(object):
    def __init__(self, name):
        self.name = name


class OtherPerson(object):
    def __init__(self, name):
        self.name = name

    @staticmethod
    def do_something(self):
        print self.name + '$$'


p = Person('alpha')
Person.do_something = OtherPerson.do_something

p.do_something() #alpha$$

答案 1 :(得分:0)

关键是将正确的参数传递给方法。 让我们仔细看看你在第一时间得到的错误:

TypeError: unbound method do_something() must be called with 
OtherPerson #instance as first argument (got nothing instead)

当你看OtherPerson.do_something时,很明显它期望一个实例作为它的第一个参数。 所以现在p.do_something引用OtherPerson.do_something,它需要第一个参数。 因此,在当前状态下,正确的呼叫将是:

p.do_something(p)

当然,这不是很好,因为你必须指定实例两次。 那是因为该方法现在是 unbound :它不知道调用它的实例,即它不知道self

我提议的解决方案包括让p.do_something引用使用 OtherPerson.fo_something p 的函数>作为第一个参数

我们有两个类FooBar,定义如下:

class Foo:
    def __init__(self, x):
        self.x = x

    def speak(self):
        print("Foo says:", self.x)


class Bar:
    def __init__(self, x):
        self.x = x

    def speak(self):
        print("Bar says:", self.x)

假设您有foo类的Foo个实例。 现在,您希望动态覆盖其speak方法,以便它调用Bar。 您只需将foo.speak重新分配给调用Bar.speak的函数。

>>> foo = Foo(2)
>>> foo.speak()
Foo says: 2
>>> foo.speak = lambda: Bar.speak(foo)
>>> foo.speak()
Bar says: 2

你可以使它更通用。 为了举例,让我们编写一个函数,它接受一个实例,一个方法名和一个目标类,并用目标类':

覆盖实例的匹配方法。
def override(instance, method_name, target_class):
    class_method = getattribute(target_class, method_name)

    def new_method(*args, **kwargs):
        return class_method(instance, *args, **kwargs)

    setattribute(instance, method_name, new_method)

您可以观察到相同的预期行为:

>>> foo = Foo(2)
>>> override(foo, "speak", Bar)
>>> foo.speak()
Bar says: 2