首页 > 解决方案 > super() 类继承,钻石问题

问题描述

为什么当我调用super()WordCounter时它调用类Vocabulary,即使它不是继承自?它不应该调用类Tokenizer吗?

class Tokenizer:
    """Tokenize text"""
    def __init__(self, text):
        print('Start Tokenizer.__init__()')
        print('End Tokenizer.__init__()')


class Vocabulary(Tokenizer):
    """Find unique words in text"""
    def __init__(self, text):
        print('Start init Vocabulary.__init__()')
        print('End init Vocabulary.__init__()')


class WordCounter(Tokenizer):
    """Count words in text"""
    def __init__(self, text):
        print('Start WordCounter.__init__()')
        super().__init__(text)
        print('End WordCounter.__init__()')


class TextDescriber(WordCounter, Vocabulary):
    """Describe text with multiple metrics"""
    def __init__(self, text):
        print('Start init TextDescriber.__init__()')
        super().__init__(text)
        print('End init TextDescriber.__init__()')


td = TextDescriber('row row row your boat')

输出:

Start init TextDescriber.__init__()
Start WordCounter.__init__()
Start init Vocabulary.__init__()
End init Vocabulary.__init__()
End WordCounter.__init__()
End init TextDescriber.__init__()

标签: pythoninheritancesuperclass

解决方案


钻石继承总是有点乱。每种语言都有自己的怪癖,Python 也不例外。(请注意,我在解释 Python 中的“新样式”类。Python 2 中也有“经典”类,它们的行为不同)

Python 对所有继承所做的事情是,如果当前类未实现请求的方法/属性,则呈现检查父类的顺序。您可以动态检查此方法解析顺序。你的例子产生

>>> print(TextDescriber.__mro__)
(<class '__main__.TextDescriber'>, <class '__main__.WordCounter'>, <class '__main__.Vocabulary'>, <class '__main__.Tokenizer'>, <class 'object'>)

如您所见,Python 选择从左到右,然后才在层次结构中下降(完整细节)。

什么super()是调用 this 中的下一个方法__mro__。该链在 处停止Vocabulary.__init__(),因为该方法不需要super().__init__()链继续。

如果您在 中包含一个super().__init__()调用Vocabulary.__init__(),这将按预期工作:

Start init TextDescriber.__init__()
Start WordCounter.__init__()
Start init Vocabulary.__init__()
Start Tokenizer.__init__()
End Tokenizer.__init__()
End init Vocabulary.__init__()
End WordCounter.__init__()
End init TextDescriber.__init__()

推荐阅读