Python self和super在多重继承中

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:

  1. super(),(Pizza, OrganicDoughFactory) (原创):'Making pie with pure untreated wheat dough'
  2. self,(Pizza, OrganicDoughFactory):'Making pie with pure untreated wheat dough'
  3. super(),(OrganicDoughFactory, Pizza):'Making pie with insecticide treated wheat dough'
  4. 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的其余部分).