Python super()类继承,菱形问题

Python super()类继承,菱形问题,python,inheritance,superclass,Python,Inheritance,Superclass,为什么当我在类WordCounter中调用super()时,它调用类词汇表,即使它不是继承自?它不应该调用classTokenizer class Tokenizer: """Tokenize text""" def __init__(self, text): print('Start Tokenizer.__init__()') print('End Tokenizer.__init__()') class Vocabulary(Tokeni

为什么当我在类
WordCounter
中调用
super()
时,它调用类
词汇表
,即使它不是继承自?它不应该调用class
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__()

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

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

>>>打印(TextDescriber.\uuuuMRO\uuuuuuu)
(, , )
如您所见,Python选择从左到右,然后才在层次结构中下降()

super()
所做的是调用此
中的下一个方法。此链在
词汇表处停止。\uuuu init\uuu()
,因为此方法没有
super()。\uuuu init\uuu()
调用链继续

如果在
词汇表中包含一个
super()。\uuuuu init\uuuuu()
调用。\uuuu init\uuuuuu()
,这将按预期工作:

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__()

感谢@Niobos解释MRO,但这并没有告诉我为什么它选择词汇表而不是标记器?比如它背后的逻辑是什么?这就是Python定义继承顺序的方式。如果您想了解更多关于所有边缘情况的信息,我已经添加了一个完整规范的链接。@Kashan。请记住,在
WordCounter中调用
super()。\uuuuu init\uuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuuu。这两个参数的意思是“使用
self
的mro,从
WordCounter
开始”。我们习惯于看到
self
属于
WordCounter
类型,或者从中获得单一继承。如果不是这样的话,
WordCounter
的父对象可能不是mro中的下一个对象,正如您在这里看到的。这就是答案中“super()
所做的是调用
\uumro\uuuu
中的下一个方法”这句话的意思。