1

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

[编辑:旧代码并没有真正捕捉到我的问题,我正在重写以使其更清晰。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 has no attribute '_x'”而不是我的预期值 50。显然,Bar 测试中的 self 仍然指的是 Bar,而不是实际调用该方法的 Foo . 我本来希望它是 Bar 中的内部 Foo self._foo 字段。

我怀疑我的问题与名称修改有关,但是当我的 self 字段被覆盖时,我无法找到描述性来源。大多数示例似乎是当我从不同的类继承时。

4

3 回答 3

1

似乎在 Bar.test 你想要:

print self._foo._x * 10
于 2013-04-08T22:15:49.640 回答
1

关于 Python 中的类如何工作的简短课程:存储在类对象(“方法”)上的任何函数都由将方法绑定到您使用的类或实例的描述符(描述如何从对象中获取属性)自动获取为拿到它,为实现它。

例如:

Foo.test 

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

Foo().test 

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

所以,你想要做的是:

  1. 从类中获取原始函数(而不是通过描述符)testBar
  2. 将此函数绑定到Foo
  3. 将此函数存储在 foo 实例上

所以,这就是你的做法:

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

有关描述符的更多详细信息,请参阅此问题

于 2013-04-08T22:49:11.160 回答
0

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

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

于 2013-04-08T22:20:44.050 回答