правильный способ использования super (передача аргументов)
Итак, я следовал Python супер считается вредным, и пошел проверить его примеры.
, пример 1-3, который должен показать правильный способ вызова
super при обращении __init__ методы, которые ожидают разные аргументы, flat-out не работает.вот что я получил:
~ $ python example1-3.py
MRO: ['E', 'C', 'A', 'D', 'B', 'object']
E arg= 10
C arg= 10
A
D arg= 10
B
Traceback (most recent call last):
File "Download/example1-3.py", line 27, in <module>
E(arg=10)
File "Download/example1-3.py", line 24, in __init__
super(E, self).__init__(arg, *args, **kwargs)
File "Download/example1-3.py", line 14, in __init__
super(C, self).__init__(arg, *args, **kwargs)
File "Download/example1-3.py", line 4, in __init__
super(A, self).__init__(*args, **kwargs)
File "Download/example1-3.py", line 19, in __init__
super(D, self).__init__(arg, *args, **kwargs)
File "Download/example1-3.py", line 9, in __init__
super(B, self).__init__(*args, **kwargs)
TypeError: object.__init__() takes no parameters
кажется,object сам нарушает один из лучших методов, упомянутых в документе, который заключается в том, что методы, которые используют super должны признать *args и **kwargs.
теперь, очевидно, г-н Найт ожидал, что его примеры будут работать, так это то, что было изменено в последних версиях Python? Я проверил 2.6 и 2.7, и он не на обоих.
Так каков же правильный способ решения этой проблемы?
3 ответов:
иногда два класса могут иметь некоторые общие имена параметров. В этом случае вы не можете вытащить пары ключ-значение из
**kwargsили удалить их из*args. Вместо этого вы можете определитьBaseкласс, который в отличие отobject, поглощает/игнорирует аргументы:class Base(object): def __init__(self, *args, **kwargs): pass class A(Base): def __init__(self, *args, **kwargs): print "A" super(A, self).__init__(*args, **kwargs) class B(Base): def __init__(self, *args, **kwargs): print "B" super(B, self).__init__(*args, **kwargs) class C(A): def __init__(self, arg, *args, **kwargs): print "C","arg=",arg super(C, self).__init__(arg, *args, **kwargs) class D(B): def __init__(self, arg, *args, **kwargs): print "D", "arg=",arg super(D, self).__init__(arg, *args, **kwargs) class E(C,D): def __init__(self, arg, *args, **kwargs): print "E", "arg=",arg super(E, self).__init__(arg, *args, **kwargs) print "MRO:", [x.__name__ for x in E.__mro__] E(10)доходность
MRO: ['E', 'C', 'A', 'D', 'B', 'Base', 'object'] E arg= 10 C arg= 10 A D arg= 10 Bобратите внимание, что для этой работы,
Baseдолжно быть предпоследний класс В MRO.
если вы собираетесь иметь много наследственности (это так), я предлагаю вам передать все параметры с помощью
**kwargs, а потомpopих сразу после их использования (если вы не нуждаетесь в них в высших классах).class First(object): def __init__(self, *args, **kwargs): self.first_arg = kwargs.pop('first_arg') super(First, self).__init__(*args, **kwargs) class Second(First): def __init__(self, *args, **kwargs): self.second_arg = kwargs.pop('second_arg') super(Second, self).__init__(*args, **kwargs) class Third(Second): def __init__(self, *args, **kwargs): self.third_arg = kwargs.pop('third_arg') super(Third, self).__init__(*args, **kwargs)Это самый простой способ решить подобную проблему.
third = Third(first_arg=1, second_arg=2, third_arg=3)
как поясняется в питон супер() считается супер, один из способов состоит в том, чтобы класс съел аргументы, которые он требует, и передал остальное. Таким образом, когда цепочка вызовов достигает
objectвсе аргументы были съедены, иobject.__init__будет вызываться без аргументов (как и ожидалось). Поэтому ваш код должен выглядеть так:class A(object): def __init__(self, *args, **kwargs): print "A" super(A, self).__init__(*args, **kwargs) class B(object): def __init__(self, *args, **kwargs): print "B" super(B, self).__init__(*args, **kwargs) class C(A): def __init__(self, arg, *args, **kwargs): print "C","arg=",arg super(C, self).__init__(*args, **kwargs) class D(B): def __init__(self, arg, *args, **kwargs): print "D", "arg=",arg super(D, self).__init__(*args, **kwargs) class E(C,D): def __init__(self, arg, *args, **kwargs): print "E", "arg=",arg super(E, self).__init__(*args, **kwargs) print "MRO:", [x.__name__ for x in E.__mro__] E(10, 20, 30)
Comments