Mar*_*urí 15 python inheritance self super method-resolution-order
在Raymond Hettinger 在PyCon 2015上的演讲" 超级考虑超级发言 "中,他解释了super
在多重继承环境中使用Python 的优势.这是雷蒙德在演讲中使用的一个例子:
class DoughFactory(object):
def get_dough(self):
return 'insecticide treated wheat dough'
class Pizza(DoughFactory):
def order_pizza(self, *toppings):
print('Getting dough')
dough = super().get_dough()
print('Making pie with %s' % dough)
for topping in toppings:
print('Adding: %s' % topping)
class OrganicDoughFactory(DoughFactory):
def get_dough(self):
return 'pure untreated wheat dough'
class OrganicPizza(Pizza, OrganicDoughFactory):
pass
if __name__ == '__main__':
OrganicPizza().order_pizza('Sausage', 'Mushroom')
Run Code Online (Sandbox Code Playgroud)
有人在台下问雷蒙德有关使用的差异self.get_dough()
,而不是super().get_dough()
.我对Raymond的简要回答并不是很了解,但我编写了这个例子的两个实现来看看差异.两种情况的输出相同:
Getting dough
Making pie with pure untreated wheat dough
Adding: Sausage
Adding: Mushroom
Run Code Online (Sandbox Code Playgroud)
如果您将班级订单OrganicPizza(Pizza, OrganicDoughFactory)
改为OrganicPizza(OrganicDoughFactory, Pizza)
使用self.get_dough()
,您将获得以下结果:
Making pie with pure untreated wheat dough
但是,如果您使用super().get_dough()
这是输出:
Making pie with insecticide treated wheat dough
我理解super()
雷蒙德解释的行为.但是self
多继承场景中的预期行为是什么?
jon*_*rpe 12
只是为了澄清,有四种情况,基于改变第二行Pizza.order_pizza
和定义OrganicPizza
:
super()
,(Pizza, OrganicDoughFactory)
(原创):'Making pie with pure untreated wheat dough'
self
,(Pizza, OrganicDoughFactory)
:'Making pie with pure untreated wheat dough'
super()
,(OrganicDoughFactory, Pizza)
:'Making pie with insecticide treated wheat dough'
self
,(OrganicDoughFactory, Pizza)
:'Making pie with pure untreated wheat dough'
案例3.令你感到惊讶的是; 如果我们切换继承的顺序但仍然使用super
,我们显然最终会调用原始的DoughFactory.get_dough
.
什么super
确实是问"这是在MRO(方法解析顺序)下一个?" 那OrganicPizza.mro()
看起来像什么?
(Pizza, OrganicDoughFactory)
: [<class '__main__.OrganicPizza'>, <class '__main__.Pizza'>, <class '__main__.OrganicDoughFactory'>, <class '__main__.DoughFactory'>, <class 'object'>]
(OrganicDoughFactory, Pizza)
: [<class '__main__.OrganicPizza'>, <class '__main__.OrganicDoughFactory'>, <class '__main__.Pizza'>, <class '__main__.DoughFactory'>, <class 'object'>]
这里的关键问题是:后来发生了 Pizza
什么?当我们super
从内部调用时Pizza
,Python将会找到get_dough
*.对于1.和2.它是OrganicDoughFactory
,所以我们得到纯净,未经处理的面团,但是对于3.和4.它是原始的,经过杀虫剂处理的DoughFactory
.
为什么self
不同呢?self
永远是实例,所以Python get_dough
从MRO的开始就寻找.在这两种情况下,如上所示,OrganicDoughFactory
在列表中早于DoughFactory
,这就是为什么self
版本总是未经处理的面团; self.get_dough
总是解决OrganicDoughFactory.get_dough(self)
.
*我认为这super
在Python 2.x 中使用的双参数形式中实际上更清楚,这将是super(Pizza, self).get_dough()
; 第一个参数是要跳过的类(即Python在该类之后查看MRO的其余部分).