在Python中覆盖字段的方法

时间:2013-04-08 22:10:13

标签: python oop overwrite

我有一个自定义类,我在第二个类中实例化两次:

[编辑:旧代码并没有真正捕捉到我的问题,我正在重写以使其更清晰。 Foo将通过使用回调函数来处理网络事件(我需要多个连接,因此Bar将具有多个Foo字段并且不能仅继承)。在Bar类中,我想覆盖回调以执行不同的操作。在Foo中重写callb将不起作用,因为我在其他实例中继承了它]

class Foo(object):
    def __init__(self, x):
        self._x = x
        #When an event happens, call callb()
        self.on_certain_event(callback=callb)

    def callb(self):
        print self._x

    def run(self):
        waitForEventsInfinitely() #

class Bar(object):
    def __init__(self):
        self._foo = Foo(5)
        #OVERWRITE THE EXISTING CALLBACK METHOD IN THE Foo CLASS!
        self._foo.callb = self.callb

    def callb(self):
        print self._x * 10

    def run(self):
        waitForEventsInfinitely() # Not going to actually write t

f = Foo(2)
f.run()
b = Bar()
b.run()

[在Foo中调用run()时,它可以正常工作。但是,我不能用Bar覆盖Foo的callb方法 - 应该由Foo引用的self._x试图从Bar调用

然而,当运行代码时,我收到错误“Bar没有属性'_x'”,而不是我预期的值50.显然,Bar的测试中的self仍然指的是Bar,而不是实际的Foo调用方法。我本来以为它是Bar中的内部Foo self._foo字段。

我怀疑我的问题与名称修改有关,但是当我在自己的字段上覆盖了他们的方法时,我无法找到描述性的来源。大多数例子似乎都是在我从一个不同的类继承的时候。

3 个答案:

答案 0 :(得分:1)

似乎在Bar.test中你想要:

print self._foo._x * 10

答案 1 :(得分:1)

关于Python中的类如何工作的简短课程:存储在类对象上的任何函数(“方法”)都由descriptor(它描述了如何从对象获取属性)自动获取,这些函数绑定了这些方法到你曾经得到它的类或实例。

例如:

Foo.test 

是类Foo的未绑定方法:这是由Foo上的描述符创建的对象,它知道它是从类对象中获取的

Foo().test 

是类Foo 实例的绑定方法:此方法存储用于获取函数的Foo实例。当您调用结果对象时,此实例将自动作为第一个参数传递,这就是您在定义方法时将self作为第一个参数的原因。

所以,你要做的是:

  1. 从类test获取原始函数Bar(不是通过描述符)
  2. 将此功能绑定到Foo
  3. 的实例
  4. 将此功能存储在foo实例
  5. 所以,你就是这样做的:

    import types 
    
    class Bar(object):
        def __init__(self):
            self._foo = Foo(5)
    
            raw_function = Bar.test_Bar.__func__                        # 1)
            bound_to_foo = types.MethodType(raw_function, self._foo)    # 2)    
            self._foo.test = bound_to_foo                               # 3)
    
        def test(self):
            print self._x * 10
    

    有关描述符的详细信息,请参阅this question

答案 2 :(得分:0)

如果查看代码,当你调用b.test时,就是直接在Bar实例上调用该方法;根本没有提到Foo的实例。 b没有名为_x的成员,因此出错。要获得您期望的行为,您必须调用b._foo.test。这将为您提供50的预期结果。

如果您希望能够直接调用b.test,请将self._x更改为self._foo._x。这样您就不必更改_foo的任何方法。我不确定为什么你可以在你可以使用继承时为对象分配不同的方法。