我有以下类继承架构:
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._configure
替换A._configure(self)
,但这看起来很丑陋而且非OOP:现在每个可能被继承的类都应该重复它每个方法调用的名称? self
的美丽和简洁在哪里?
答案 0 :(得分:3)
班级setup
中的B
方法调用super
,因此它从setup
调用A
方法...这是执行的顺序你的方法:
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")
这意味着Z.setup
通过继承调用B.setup
,后者通过调用A.setup
的{{1}}调用super
。 B._configure
再次调用B.setup
并在B._configure
之后返回。
希望这表明(或多或少)
更新:以下是对正在发生的事情的一点解释:您正在定义一个类append
,其中包含公共方法Z
和私有方法setup
。这些方法未在_configure
类中定义,而是在其父类Z
上定义。但是,由于继承,您仍然可以致电B
和Z.setup
。
现在,Z._configure
方法使用Z.setup
类中的定义才能工作。这会调用B
以便在super
时调用A.setup
中定义的代码,因此当调用方法Z
时,将使用哪个定义?正如我们_configure
(即Z
是self
的实例),将被调用的方法将是Z
,因为这是继承所做的。
再次查看代码:您将Z._configure
首先在B
中定义的_configure
方法覆盖。由于A
中没有对super
的调用,如果对象是继承自B._configure
的类的实例,则永远不会调用A._configure
。
TL; DR :如果A
定义A._configure
而未调用超级,则无法从Z
致电B
。这是继承。如果您想致电_configure
,请不要覆盖A.configure
中的方法或使用B
。
希望这有帮助! :)
答案 1 :(得分:1)
最后我明白了,必要的魔法称为name mangling或name scrambling。
解决方案就像在配置方法的名称中使用两个下划线一样简单。当Python看到这样有趣的命名方法(或其他属性)时,它将以静默方式将重命名为_A__configure
,这样即使用户(意外或非意外)覆盖了它,也会调用正确的方法。 / p>
(到现在为止,我认为“两个下划线”是为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:~$