为什么可以调用超类没有的方法

时间:2019-05-18 15:27:22

标签: python python-2.7 multiple-inheritance superclass method-resolution-order

我正在阅读源代码,该源代码阻碍了Python 2.7的paxos算法。在代码中,有许多方法调用超类的方法,而在超类中完全没有此方法,并且这两个方法的名称始终相同。这是Python的特殊功能吗? 例如。超级(SimpleSynchronizationStrategyMixin,self).set_messenger(messenger) SimpleSynchronizationStrategyMixin的超类是不包含方法“ set_messenger”的对象。这行代码所属的方法的确切名称也是“ set_messenger”

class SimpleSynchronizationStrategyMixin(object):

    sync_delay = 10.0

    def set_messenger(self, messenger):
        super(SimpleSynchronizationStrategyMixin,self).set_messenger(messenger)

        def sync():
            self.messenger.send_sync_request(random.choice(self.peers), self.instance_number)

        self.sync_task = task.LoopingCall(sync)
        self.sync_task.start(self.sync_delay)


    def receive_sync_request(self, from_uid, instance_number):
        if instance_number < self.instance_number:
            self.messenger.send_catchup(from_uid, self.instance_number, self.current_value)


    def receive_catchup(self, from_uid, instance_number, current_value):
        if instance_number > self.instance_number:
            print 'SYNCHRONIZED: ', instance_number, current_value
            self.advance_instance(instance_number, current_value, catchup=True)

1 个答案:

答案 0 :(得分:1)

您发布的代码确实确实很奇怪,并且单独使用该类确实会失败。例如,使用下面的最小示例:

class SimpleSynchronizationStrategyMixin(object):

    def set_messenger(self, messenger):
        super(SimpleSynchronizationStrategyMixin,self).set_messenger(messenger)
        print('test')


test = SimpleSynchronizationStrategyMixin()
test.set_messenger(None)

会产生一个错误,就像您期望的那样:

AttributeError: 'super' object has no attribute 'set_messenger'

但是,该类的名称揭示了答案:它是一个“ mixin”类,该类旨在与其他类进行混合。因此,该类仅添加了某些功能,并且可以对超级对象中存在的方法进行假设(对于最终对象,该方法不是 object

为了说明这一点,让我们用以下代码扩展上面的示例:

class SomeOtherClass(object):

    def set_messenger(self, messenger):
        print('setting the messenger to %s.' % repr(messenger))


class Demo(SimpleSynchronizationStrategyMixin, SomeOtherClass):

    def demo(self):
        self.set_messenger('some messenger')


demo = Demo()
demo.demo()

此处,set_messenger中定义了SomeOtherClass方法。然后Demo类将SomeOtherClass与mixin一起使用来创建最终对象。调用demo()时,它将打印:

setting the messenger to 'some messenger'.
test

请注意,超类的顺序很重要。如果您要写class Demo(SomeOtherClass, SimpleSynchronizationStrategyMixin),则不会打印“ test”行。

有关特定的paxos示例,请参见server.py,其中包含:

class ReplicatedValue(DedicatedMasterStrategyMixin, ExponentialBackoffResolutionStrategyMixin, SimpleSynchronizationStrategyMixin, BaseReplicatedValue):
    """
    Mixes the dedicated master, resolution, and synchronization strategies into the base class
    ""

在这里您可以看到许多mixin类已“添加”到BaseReplicatedValue以创建ReplicatedValue

请注意,super()并不总是返回“父”对象。如果方法DedicatedMasterStrategyMixin.propose_update(self, ...)调用super(DedicatedMasterStrategyMixin, self).propose_update(...),它将根据Method Resolution Order (MRO)找到下一个propose_update()方法。简而言之,它在所有基类中从左到右查找,并返回找到的第一个方法。这样,每个方法都可以调用super(),而不必知道哪个类是“父”类,因此仍然可以链接所有必需的方法。以下示例代码对此进行了演示:

class Base(object):
    def test(self):
        # NB: No super() call in the base class!
        print('Test Base')
        print('')

class MixinX(object):
    def test(self):
        print('Test X')
        super(MixinX, self).test()

class MixinY(object):
    def test(self):
        print('Test Y')
        super(MixinY, self).test()

class MixinZ(object):
    def test(self):
        print('Test Z')
        super(MixinZ, self).test()

class Final(Base):
    pass

class FinalX(MixinX, Base):
    pass

class FinalXYZ(MixinX, MixinY, MixinZ, Base):
    pass

class FinalZYX(MixinZ, MixinY, MixinX, Base):
    pass

class WrongOrder(Base, MixinX, MixinY, MixinZ):
    pass

class MixinsOnly(MixinX, MixinY, MixinZ):
    pass


"""
>>> Final().test()
Test Base

>>> FinalX().test()
Test X
Test Base

>>> FinalXYZ().test()
Test X
Test Y
Test Z
Test Base

>>> FinalZYX.test()
Test Z
Test Y
Test X
Test Base

>>> WrongOrder().test()
Test Base

>>> MixinsOnly().test()
Test X
Test Y
Test Z
Traceback (most recent call last):
  File "superdemo.py", line 36, in <module>
    MixinsOnly().test()
  File "superdemo.py", line 9, in test
    super(MixinX, self).test()
  File "superdemo.py", line 14, in test
    super(MixinY, self).test()
  File "superdemo.py", line 19, in test
    super(MixinZ, self).test()
AttributeError: 'super' object has no attribute 'test'

>>> FinalXYZ.mro()
[<class '__main__.FinalXYZ'>, <class '__main__.MixinX'>, <class '__main__.MixinY'>, <class '__main__.MixinZ'>, <class '__main__.Base'>, <type 'object'>]
"""