2010-09-17 28 views
9

önce, "Expert Python Programming" kitabından biraz alıntı yapalım:Python'da süper ve klasik çağrıları karıştırma

Aşağıdaki örnekte, __init__ yöntemini kullanarak temel sınıflarını çağıran bir C sınıfı B sınıfının iki kez çağrılmasını sağlar!

class A(object): 
    def __init__(self): 
     print "A" 
     super(A, self).__init__() 

class B(object): 
    def __init__(self): 
     print "B" 
     super(B, self).__init__() 

class C(A,B): 
    def __init__(self): 
     print "C" 
     A.__init__(self) 
     B.__init__(self) 

print "MRO:", [x.__name__ for x in C.__mro__] #prints MRO: ['C', 'A', 'B', 'object'] 
C() #prints C A B B 

ve son olarak, burada neler olup bittiğine dair bir açıklama:

Bu, C örneği ile yapılan A .__ init __ (self) çağrısından kaynaklanır. böylece süper (A, self) .__ init __() B çağrısı yapıcısını çağırır. Başka bir deyişle, süper tüm sınıf hiyerarşisinde kullanılmalıdır. Sorun şu ki, bu hiyerarşinin bir kısmı üçüncü taraf kodunda yer almaktadır.

Neden "super(A, self).__init__(), B'nin yapıcısını çağırıyor" diye bir fikrim yok. Lütfen bu anı açıkla. Çok teşekkürler.

cevap

4

super belgeleri söylüyor:

İade delegeleri yöntem türünde bir ebeveyn veya kardeş sınıfa çağıran bir vekil nesnesi. Bu, bir sınıfta geçersiz kılınan devralınan yöntemlere erişmek için kullanışlıdır. Arama sırası, yazının kendisinin atlanması dışında getattr() tarafından kullanılanla aynıdır. Eğer C içinden A.__init__(self) çalıştırdığınızda

super(A, self)<super: <class 'A'>, <C object>> dönecektir. Örnek olarak C (<C object>) C'nin kalıtım hiyerarşisindeki tüm sınıflar alınır. Ve hepsine __init__ çağrı verilir. Sonuç olarak 'B' iki kere çağrıldığını görüyorsunuz.

Bunu doğrulamak için başka bir sınıf 'Z' ekleyin ve 'C' 'yi de' Z 'olarak atayalım. Ne olduğunu görün.

Bu durumda
class Z(object): 
    def __init__(self): 
     print "Z" 
     super(Z, self).__init__() 

class C(A, B, Z):  
    def __init__(self): 
     print "C" 
     A.__init__(self) 
     B.__init__(self) 
     Z.__init__(self) 

, AB ve Z arayacak. B, Z'u da arayacaktır.

9

Bu davranışı anlamak için, temel sınıfı değil, super çağrılarını anlamalısınız, ancak __mro__'daki sıradaki sonraki eşleme yöntemini arar. Bu nedenle, super(A, self).__init__() numaralı çağrı __mro__ == ['C', 'A', 'B', 'object']'a bakar, B'u eşleşen bir yöntemle bir sonraki sınıf olarak görür ve B yöntemini (yapıcı) çağırır.

Eğer C

class C(A,B): 
    def __init__(self): 
     print "C1" 
     A.__init__(self) 
     print "C2" 
     B.__init__(self) 
     print "C3" 

geçerseniz gösterir

MRO: ['C', 'A', 'B', 'object'] 
C1 
A 
B 
C2 
B 
C3 

olsun nasıl A aramaların B yapıcısı.

+1

teşekkürler. Bir soru - A sınıfı bir kurucu içinde "süper (A, self) .__ init __()" çağrıldığında, onun "self" argümanı, yeni örnek verdiğimiz C örneğimize eşit olduğu doğru mu? – varnie

+2

@varnie: evet. 'Self'in gerçekten bir' C 'örneğini görmek için' __init __() 'yönteminin içinde super (A, self)' yazdırabilirsiniz. –