super'i kullanmanın doğru yolu (argüman geçme)


109

Bu yüzden Python'un Süper Zararlı Olarak Düşünülmesini takip ediyordum ve örneklerini test etmeye gittim.

Ancak, farklı argümanlar bekleyen yöntemleri işlerken doğru arama yöntemini göstermesi beklenen Örnek 1-3 , düz çıkış çalışmaz.super__init__

Bu benim aldığım:

~ $ 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

O görünüyor objectkendisi yöntemlerin hangi kullanım olmasıdır belgede, belirtilen en iyi uygulamaların birini ihlal superkabul etmelidir *argsve **kwargs.

Şimdi, belli ki Bay Knight, örneklerinin işe yaramasını bekliyordu, peki bu Python'un son sürümlerinde değişen bir şey mi? 2.6 ve 2.7'yi kontrol ettim ve her ikisinde de başarısız.

Peki bu problemle başa çıkmanın doğru yolu nedir?


2
Tercih ettiğim yöntem: Düz ve basit miras hiyerarşileri.
millimoose

20
Ayrıca okumalısınız "süper kabul Python'un super ()" dengeli bir görünüm :) olsun
Björn Pollex

@ BjörnPollex: Teşekkürler! Bağlantınız soruya bir cevap sağlar: 'dan miras alan bir "kök sınıf" yazabilirsiniz objectve bu, object' s 'ları __init__doğru çağırmanızı sağlar.
cha0site

5
Not olduğu __init__üzerinde objectsessizce yoksayar Python 2.5 üzerinde herhangi bir parametre. Bu Python 2.6'da değişti.
Wilfred Hughes

1
@Wilfred: Hey, Asıl soruyu yanıtladığınız için teşekkürler! Şimdi makalenin neden güncel olmadığını biliyorum!
cha0site

Yanıtlar:


116

Bazen iki sınıfın ortak bazı parametre adları olabilir. Bu durumda, anahtar / değer çiftlerini çıkaramaz **kwargsveya onlardan kaldıramazsınız *args. Bunun yerine, argümanları emen / yok sayan bir Basesınıf tanımlayabilirsiniz 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)

verim

MRO: ['E', 'C', 'A', 'D', 'B', 'Base', 'object']
E arg= 10
C arg= 10
A
D arg= 10
B

Bunun işe yaraması Baseiçin MRO'daki sondan bir önceki sınıf olması gerektiğini unutmayın.


4
Gerekmiyor Basediyoruz super(Base, self).__init__()?
cha0site

4
Bunun çalışması Baseiçin MRO'nun sonunda gelmelidir (hariç object). Arama object.__init__hiçbir şey yapmaz, bu yüzden aramamakta sorun yoktur super(Base, self).__init__(). Aslında, hattın sonu olan super(Base, self).__init__()noktayı eve götürmeyi dahil etmemek daha açık olabilir diye düşünüyorum Base.
unutbu

27

Çok fazla kalıtıma sahip olacaksanız (burada durum budur) **kwargs, tüm parametreleri kullanarak geçmenizi öneririm ve sonra popbunları kullandıktan hemen sonra (üst sınıflarda ihtiyacınız olmadıkça).

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)

Bu tür sorunları çözmenin en basit yolu budur.

third = Third(first_arg=1, second_arg=2, third_arg=3)

7

Python'un süper () süper kabul edilen kitabında açıklandığı gibi , bir yol, sınıfın gerektirdiği argümanları yemesini sağlamak ve gerisini başkalarına aktarmaktır. Böylece, çağrı zinciri ulaştığında object, tüm argümanlar yenilmiş ve object.__init__argümansız çağrılacaktır (beklediği gibi). Yani kodunuz şöyle görünmelidir:

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)

Peki ya ne olacak E(arg = 10)? Bu yöntemi sevmiyorum, kullanmak için MRO'yu önceden bilmem gerekiyor. Miras alan bir "kök sınıf" yazdığım diğer yöntem objectçok daha temiz görünüyor.
cha0site

Bu yöntem, çağrılan işlevler bağımsız değişken adlarını paylaşmıyorsa yararlıdır. Çok fazla pratik deneyimim olmadığını itiraf ediyorum super, bu nedenle bu yaklaşım aslında oldukça teorik olabilir.
Björn Pollex
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.