1

我有以下类继承架构:

object <- A <- B <- Z

现在每个类都有公共setup()方法,它调用其他“私有”方法_configure(),其中包含我不想弄乱的加载代码setup()。关键是让每个班级“知道”如何设置自己,并在其他执行之前完成。

因此,在 Z 的实例上调用 setup 时我想要的是同时运行A的设置和 B 的设置(顺序现在不是特别重要),而每个设置都使用在其自己的类中定义的 _configure。

现在跟随脚本

#!/usr/bin/python

class A(object):

    def __init__(self):
        self.configured = []
        self.set_up = []

    def _configure(self):
        self.configured.append("A")

    def setup(self):
        self._configure()       # calls B._configure()!
        self.set_up.append("A")

class B(A):

    def _configure(self):
        self.configured.append("B")

    def setup(self):
        super(B, self).setup()
        self._configure()
        self.set_up.append("B")

class Z(B):
    pass

if __name__ == "__main__":
    z = Z()
    z.setup()
    print "configured: %s" % z.configured
    print "set up: %s" % z.set_up

运行B._configure()两次,因此返回

me@here:~$ ./t.py 
configured: ['B', 'B']
set up: ['A', 'B']
me@here:~$

而不是configured: ['A', 'B']....

有人可以向我解释一下吗?我应该如何确保A.setup调用A._configure

解决方法:目前有效的是替换self._configureA._configure(self),但这看起来很丑陋且非 OOP:现在每个可能被继承的类都应该在每个方法调用中重复其名称?的美丽和简洁在self哪里?

4

2 回答 2

3

The setup method in class B calls super, so it calls the setup method from A... This is the order of execution of your methods:

Z.setup()
  B.setup()
    A.setup (via super)
      B._configure
        B.configured.append("B")
      B.setup.append("A")
    B._configure
      B.configured.append("B")
  B.set_up.append("B")

This means that Z.setup calls B.setup via inheritance, which calls A.setup via super, which calls B._configure. B.setup calls again B._configure and return after the append.

Hope this makes it clear (more or less)

UPDATE: Here's a little explanation of what's happening: You are defining a class Z which has a public method setup and a private method _configure. Those methods are not defined in Z class but on its parent, class B. But you can still call Z.setup and Z._configure thanks to inheritance.

Now, the Z.setup method uses the definition in B class in order to work. This calls super in order to call the code defined in A.setup while still being Z, so when the method _configure is called, which definition will be used? As we are Z (that is, self is an instance of Z), the method that will be called will be Z._configure, because that's what inheritence does.

Look at the code again: you are overwriting in B the _configure method first defined in A. As there's no call to super in B._configure, A._configure will never be called if the object is an instance of a class that inherits from A.

TL;DR: You can't call A._configure from Z if B defines _configure without calling super. That's inheritance. If you want to call A.configure, either don't overwrite the method in B or use super.

Hope this helps! :)

于 2013-07-03T15:54:13.717 回答
1

终于我明白了,必要的魔法叫做name manglingname scrambling

解决方法很简单,只需在配置方法的名称中使用两个下划线即可。当 Python 看到这种有趣的命名方法(或其他属性)时,它会默默地将其重命名_A__configure,这样即使用户(无意或无意)覆盖了它,也会调用正确的方法。

(直到现在,我认为“两个下划线”是为 Python 内部保留的,一直谦虚地避免它们......)

固定代码:

#!/usr/bin/python

class A(object):

    def __init__(self):
        self.configured = []
        self.set_up = []

    def __configure(self):
        self.configured.append("A")

    def setup(self):
        self.__configure()
        self.set_up.append("A")

class B(A):

    def __configure(self):
        self.configured.append("B")

    def setup(self):
        super(B, self).setup()
        self.__configure()
        self.set_up.append("B")

class Z(B):
    pass

if __name__ == "__main__":
    z = Z()
    z.setup()
    print "configured: %s" % z.configured
    print "set up: %s" % z.set_up

返回所需的

me@here:~$ ./t.py 
configured: ['A', 'B']
set up: ['A', 'B']
me@here:~$
于 2013-07-03T17:04:45.293 回答