Python self和super在多重继承中 [英] Python self and super in multiple inheritance
问题描述
Raymond Hettinger在PyCon 2015上的演讲超级考虑超级发言他解释了在多继承上下文中使用Python中的 super
的优点。这是Raymond在演讲中使用的一个例子:
class DoughFactory(object):
def get_dough(自我):
返回'杀虫剂处理的小麦面团'
类比萨饼(DoughFactory):
def order_pizza(self,* toppings):
打印('获得面团')
dough = super()。get_dough()
print('使用%s'%面团制作馅饼)
顶部浇头:
print( '添加:%s'%顶部)
class OrganicDoughFactory(DoughFactory):
def get_dough(self):
返回'纯未经处理的小麦面团'
class OrganicPizza(Pizza,OrganicDoughFactory):
传递
如果__name__ =='__main__':
OrganicPizza() .order_pizza('Sausage','Mushroom')
观众中有人问 Raymond关于使用 self.get_dough()
而不是 super()。get_dough()
的区别。我对Raymond的简要回答并不是很了解,但是我编写了这个例子的两个实现来看看差异。两种情况下的输出相同:
获得面团
用纯未经处理的小麦面团制作馅饼
添加:香肠
添加:蘑菇
如果您从<$ c $更改班级订单c> OrganicPizza(Pizza,OrganicDoughFactory)到 OrganicPizza(OrganicDoughFactory,Pizza)
使用 self.get_dough()
,你会得到这样的结果:
用纯未加工的小麦面团做馅饼
但是如果你使用 super()。get_dough()
这是输出:
用经杀虫剂处理的小麦面团制作馅饼
我理解 super ()
雷蒙德解释的行为。但是多继承场景中 self
的预期行为是什么?
只是澄清一下,有四种情况,基于改变 Pizza.order_pizza
中的第二行以及 OrganicPizza
:
-
super()
,(Pizza, OrganicDoughFactory)
(原创):'用纯未加工的小麦面团做馅饼'
-
self
,(Pizza,OrganicDoughFactory)
:'用未经处理的纯麦制作馅饼面团'
-
super()
,(OrganicDoughFactory,Pizza)
:'用经过杀虫剂处理的小麦面团做馅饼'
-
self
,(OrganicDoughFactory,Pizza)
:'用纯未加工的小麦面团做馅饼'
案例3令您感到惊讶;如果我们切换继承顺序但仍然使用 super
,我们显然最终会调用原来的 DoughFactory.get_dough
。 / p>
超级
真的是要求这是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'>]
这里的关键问题是: <$ em> 之后的比萨
?当我们从 Pizza
里面调用 super
时,Python将会找到 get_dough
*。对于1.和2.它是 OrganicDoughFactory
,所以我们得到纯净的,未经处理的面团,但是对于3.和4.它是原始的,经过杀虫剂处理的 DoughFactory
。
为什么 self
不同,那么? self
总是实例,因此Python从一开始就寻找 get_dough
MRO。在这两种情况下,如上所示, OrganicDoughFactory
在列表中的位置早于 DoughFactory
,这就是为什么 self
版本总是得到未经处理的面团; self.get_dough
始终解析为<code> OrganicDoughFactory.get_dough(self)。
* 我认为这在Python中使用的 super
的双参数形式中更为明显2.x,这将是 super(Pizza,self).get_dough()
;第一个参数是要跳过的类(即Python在该类之后查看MRO的其余部分)。
In Raymond Hettinger's talk "Super considered super speak" at PyCon 2015 he explains the advantages of using super
in Python in multiple inheritance context. This is one of the examples that Raymond used during his talk:
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')
Somebody in the audience asked Raymond about the difference of using self.get_dough()
instead super().get_dough()
. I didn't understand very well the brief answer of Raymond but I coded the two implementations of this example to see the differences. The output are the same for both cases:
Getting dough
Making pie with pure untreated wheat dough
Adding: Sausage
Adding: Mushroom
If you alter the class order from OrganicPizza(Pizza, OrganicDoughFactory)
to OrganicPizza(OrganicDoughFactory, Pizza)
using self.get_dough()
, you will get this result:
Making pie with pure untreated wheat dough
However if you use super().get_dough()
this is the output:
Making pie with insecticide treated wheat dough
I understand the super()
behavior as Raymond explained. But what is the expected behavior of self
in multiple inheritance scenario?
Just to clarify, there are four cases, based on changing the second line in Pizza.order_pizza
and the definition of OrganicPizza
:
super()
,(Pizza, OrganicDoughFactory)
(original):'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'
Case 3. is the one that's surprised you; if we switch the order of inheritance but still use super
, we apparently end up calling the original DoughFactory.get_dough
.
What super
really does is ask "which is next in the MRO (method resolution order)?" So what does OrganicPizza.mro()
look like?
(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'>]
The crucial question here is: which comes after Pizza
? As we're calling super
from inside Pizza
, that is where Python will go to find get_dough
*. For 1. and 2. it's OrganicDoughFactory
, so we get the pure, untreated dough, but for 3. and 4. it's the original, insecticide-treated DoughFactory
.
Why is self
different, then? self
is always the instance, so Python goes looking for get_dough
from the start of the MRO. In both cases, as shown above, OrganicDoughFactory
is earlier in the list than DoughFactory
, which is why the self
versions always get untreated dough; self.get_dough
always resolves to OrganicDoughFactory.get_dough(self)
.
* I think that this is actually clearer in the two-argument form of super
used in Python 2.x, which would be super(Pizza, self).get_dough()
; the first argument is the class to skip (i.e. Python looks in the rest of the MRO after that class).
这篇关于Python self和super在多重继承中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!