2012-01-18 3 views
14

При построении встроенного типа, а также из другого класса, конструктор встроенного типа не вызывает конструктор суперкласса. Это приводит к тому, что методы __init__ не вызываются для типов, которые появляются после встроенного в MRO.Python 3 встроенных типов __init__ не вызывает super() .__ init__?

Пример:

class A: 
    def __init__(self, *args, **kwargs): 
     super().__init__(*args, **kwargs) 
     print("A().__init__()") 

class B(list, A): 
    def __init__(self, *args, **kwargs): 
     print("B().__init__() start") 
     super().__init__(*args, **kwargs) 
     print("B().__init__() end") 

if __name__ == '__main__': 
    b = B() 

В этом образце, А .__ init__ никогда не вызывается. Когда B определяется как class B(A, list), вместо этого - переключение порядка наследования - он работает по назначению (т. Е. Вызывается A____ init__).

Эта очень тонкая зависимость от порядка наследования кажется довольно не-пифонической, она предназначена именно так? Это также означает, что вы никогда не должны выводить из встроенных типов в сложные иерархии классов, потому что вы не можете знать, где встроенная функция заканчивается в MRO, когда кто-то из вас выводит из ваших классов (ужас обслуживания). Я что-то упускаю?

Дополнительно: Python версии 3.1

+0

Python никогда не имел автоматический вызов суперкласса '__init__' методов – Marcin

+2

Что бы это называет' .__ init__' с? 'list .__ init__' принимает один аргумент и выдает ошибку, если он получает больше. Даже если бы он принял произвольные другие аргументы, он выбил бы первый, и то, что увидит, будет зависеть от порядка наследования. –

+0

Аналогичный вопрос: http: // stackoverflow.com/questions/3277367/how-do-pythons-super-work-with-multiple-inheritance С приходом Guido от ответа на этот вопрос: http://python-history.blogspot.com/2010/06/method- resolution-order.html – aganders3

ответ

9

Правильное использование super() довольно тонкое и требует некоторой осторожности, если методы сотрудничающие не все имеют такую ​​же подпись. Обычная картина для __init__() методов заключается в следующем:

class A(object): 
    def __init__(self, param_a, **kwargs): 
     self.param_a = param_a 
     super(A, self).__init__(**kwargs) 

class B(A): 
    def __init__(self, param_b, **kwargs): 
     self.param_b = param_b 
     super(B, self).__init__(**kwargs) 

class C(A): 
    def __init__(self, param_c, **kwargs): 
     self.param_c = param_c 
     super(C, self).__init__(**kwargs) 

class D(B, C): 
    def __init__(self, param_d, **kwargs): 
     self.param_d = param_d 
     super(D, self).__init__(**kwargs) 

d = D(param_a=1, param_b=2, param_c=3, param_d=4) 

Обратите внимание, что это требует, чтобы все методы совместной работы, и что все методы требуют несколько совместимую подпись, чтобы убедиться, что не имеет значения, в какой момент вызывается метод.

Конструкторы встроенных типов не имеют подписей конструктора, которые позволяют участвовать в таком сотрудничестве. Даже если они действительно вызвали super().__init__(), это было бы бесполезно, если бы все подписи конструктора не были унифицированы. Поэтому, в конце концов, вы правы - они не подходят для участия в вызовах конструктора совместной работы.

super() можно использовать только в том случае, если все методы сотрудничества имеют одну и ту же подпись (например, __setattr__()) или если вы используете вышеуказанный (или аналогичный) шаблон. Однако использование super() не является единственным шаблоном для вызова методов базового класса. Если в вашем шаблоне множественного наследования нет «бриллиантов», вы можете использовать явные вызовы базового класса, например B.__init__(self, param_a). Классы с несколькими базовыми классами просто вызывают несколько конструкторов. Даже если есть бриллианты, иногда вы можете использовать явные вызовы, если вы заботитесь о том, чтобы __init__() можно было назвать несколько раз без вреда.

Если вы хотите использовать конструкторы super() в любом случае, вы действительно не должны использовать подклассы встроенных типов (за исключением object) в нескольких иерархиях бездействия. Некоторое дальнейшее чтение: