为什么当我在类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__()
钻石继承总是一团糟。每种语言都有自己的怪癖,Python也不例外。 (请注意,我在解释Python中的“新样式”类。Python2中也有“经典”类,它们的行为有所不同)
Python对于所有继承所做的工作是呈现一个顺序,在该顺序中,如果当前类未实现所请求的方法/属性,则将检查父类。您可以动态检查此方法解析顺序。您的示例产生
>>> print(TextDescriber.__mro__)
(<class '__main__.TextDescriber'>, <class '__main__.WordCounter'>, <class '__main__.Vocabulary'>, <class '__main__.Tokenizer'>, <class 'object'>)
如您所见,Python选择从左到右移动,然后才在层次结构(full details)中下降。
super()
的作用是在此__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__()