Python super () __init __ () üsulları ilə anlama

super() istifadəini anlamağa çalışıram. Görünüşdə, həm uşaq sinifləri yaradıla bilər, yalnız gözəl.

Mən iki uşağın sinifləri arasındakı faktiki fərqi maraqlandırıram.

 class Base(object): def __init__(self): print "Base created" class ChildA(Base): def __init__(self): Base.__init__(self) class ChildB(Base): def __init__(self): super(ChildB, self).__init__() ChildA() ChildB() 
2029
23 февр. 23 fevralda Mizipzor tərəfindən təyin olundu. 2009-02-23 03:30 '09 saat 03:30 'da 2009-02-23 03:30
@ 7 cavab

super() , açıq-aydın əsas sinifə müraciət etməməyə imkan verir. Amma əsas üstünlüyü hər növ komik şeylərin baş verə biləcəyi bir çox mirasçılıqdır. Əgər artıq etmədiyiniz təqdirdə super standart sənədlərə baxın.

Sintaksisin Python super(ChildB, self).__init__() dəyişdirildiyini unutmayın: super().__init__() əvəzinə super(ChildB, self).__init__() yerinə IMO-nun bir az gözəl olduğunu söyləyə bilərsiniz.

1453
23 февр. Cavab 23 fevralda Kiv tərəfindən verilir . 2009-02-23 03:37 '09 da 3:37 'da 2009-02-23 03:37

Mən super()

super istifadə etmək səbəbi çoxlu bir çox miras istifadə edə biləcək uşağın sinifləri metodun düzəldilməsi (MRO) üçün əsas sinifin növbəti funksiyasını çağırır.

Python 3-də bunu biz çağırırıq:

 class ChildB(Base): def __init__(self): super().__init__() 

Python 2-də bunu aşağıdakı kimi istifadə etməlidir:

  super(ChildB, self).__init__() 

Super olmadan, birdən çox miras istifadə etmək qabiliyyətiniz məhduddur:

  Base.__init__(self) # Avoid this. 

Aşağıda daha ətraflı izah edəcəyəm.

"Bu kodda nə fərq var?"

 class ChildA(Base): def __init__(self): Base.__init__(self) class ChildB(Base): def __init__(self): super(ChildB, self).__init__() # super().__init__() # you can call super like this in Python 3! 

Bu kodun əsas fərqi, __init__super ilə olan indirection qatını əldə __init__ . Bu, MRO-da axtarış üçün növbəti sinif __init__ müəyyən etmək üçün cari sinfi istifadə edir.

Bu fərqi Pythonda "super" dan necə istifadə edəcəyi sualına cavab verəcəyəm ? asılılıq mübadiləsibirgə bir çox mirasçılığını nümayiş etdirir.

Python super olmazsa

Burada həqiqətən sübut olan kod (C tətbiq olunur, bəzi test və ehtiyat davranışını eksik və Python-a tərcümə edilir):

 class ChildB(Base): def __init__(self): mro = type(self).mro() # Get the Method Resolution Order. check_next = mro.index(ChildB) + 1 # Start looking after *this* class. while check_next < len(mro): next_class = mro[check_next] if '__init__' in next_class.__dict__: next_class.__init__(self) break check_next += 1 

Bir az daha doğma Python kimi yazılmışdır:

 class ChildB(Base): def __init__(self): mro = type(self).mro() for next_class in mro[mro.index(ChildB) + 1:]: # slice to end if hasattr(next_class, '__init__'): next_class.__init__(self) break 

Üstün bir obyektimiz yoxdursa, bu əl kodunu hər yerdə yazmalıyıq (və ya yenidən yaratmalıyıq!) Bu üsulu həll etmək üçün doğru növbəti üsul çağırdığımıza əmin olmaq üçün!

Python 3-də nə dərəcədə sübut olunub ki, hansı sinif və nüsxə onu adlandırdığınız metoddan aydın şəkildə ifadə edir?

__class__ yığınının çərçivəsini alır və sinif ( __class__ funksiyasını sinifdə yaxınlaşdıran __class__ kimi) və bu funksiyaya aid ilk arqument olan hansı bir həll və ya həll metodu (MRO) olduğunu söyləyən bir sinif olmalıdır ki, istifadə etmək.

MRO üçün ilk arqument tələb olunduğundan, statik metodlarla super istifadə etmək mümkün deyil .

border=0

Digər cavabların tənqidi:

super () əsasən əsas sinifə toxunaraq, xoşagəlməz ola bilər, amma əsas üstünlüyü hər növ komik şeylərin baş verə biləcəyi bir çox mirasdır. Artıq bunu etmədiyiniz təqdirdə sübut üzrə standart sənədlərə baxın.

Bu olduqca həyəcan verici və bizə çox məlumat vermir, ancaq superuncu nöqtəsi ana sinif yazmaq deyil. Məsələ burasındakı metodu həll üsulu (MRO) istiqamətində aşağıdakı metodu təmin etməkdir. Bu birdən çox miras ilə əhəmiyyət kəsb edir.

Burada izah edəcəyəm.

 class Base(object): def __init__(self): print("Base init'ed") class ChildA(Base): def __init__(self): print("ChildA init'ed") Base.__init__(self) class ChildB(Base): def __init__(self): print("ChildB init'ed") super(ChildB, self).__init__() 

Və Uşaqdan sonra biz istədiyimiz asılılığı yaratmaq:

 class UserDependency(Base): def __init__(self): print("UserDependency init'ed") super(UserDependency, self).__init__() 

İndi xatırlayıram, ChildB super istifadə edir, ChildA deyil:

 class UserA(ChildA, UserDependency): def __init__(self): print("UserA init'ed") super(UserA, self).__init__() class UserB(ChildB, UserDependency): def __init__(self): print("UserB init'ed") super(UserB, self).__init__() 

UserA bağımlılığı metodu çağırır:

 >>> UserA() UserA init'ed ChildA init'ed Base init'ed <__main__.UserA object at 0x0000000003403BA8> 

UserB , çünki ChildB super istifadə edir!

 >>> UserB() UserB init'ed ChildB init'ed UserDependency init'ed Base init'ed <__main__.UserB object at 0x0000000003403438> 

Başqa cavab üçün tənqid

Heç bir halda, başqa bir cavab ilə göstərildiyi kimi, aşağıda göstərilənləri etməlisiniz. Çünki ChildB alt sinifində səhvlər olacaqsınız:

  super(self.__class__, self).__init__() # Don't do this. Ever. 

(Bu cavab akıllıca və ya xüsusilə maraqlı deyil, lakin şərhlərdə və 17-dən çox downvote-dən birbaşa tənqid olunmasına baxmayaraq, cavab vermə mexanizmi görkəmli redaktoru öz problemini həll etməyincə onu təklif etməyə borcludur.)

Şərhlər: Bu cavabı super kimi çağırırdı:

 super(self.__class__, self).__init__() 

Bu tamamilə səhvdir. super , uşaq sinifləri üçün MRO-da (bu cavabın birinci hissəsinə baxın) növbəti valideynləri axtarmağa imkan verir. Əgər uşağın müalicə metodunda olduğumuzu sübut etsəniz, ehtimal ki, məntiqi bir uğursuzluqa (məsələn, məsələnin nümunəsində) və ya RuntimeError gətirib çıxaracaq recursiona səbəb olan simli (ehtimal ki, bu) recursion dərinliyi aşdıqda.

 >>> class Polygon(object): ... def __init__(self, id): ... self.id = id ... >>> class Rectangle(Polygon): ... def __init__(self, id, width, height): ... super(self.__class__, self).__init__(id) ... self.shape = (width, height) ... >>> class Square(Rectangle): ... pass ... >>> Square('a', 10, 10) Traceback (most recent call last): File "<stdin>", line 1, in <module> File "<stdin>", line 3, in __init__ TypeError: __init__() missing 2 required positional arguments: 'width' and 'height' 
445
25 нояб. Cavab 25 noyabrda Aaron Hall tərəfindən verilir. 2014-11-25 22:00 '14 saat 22:00 'də 2014-11-25 22:00 ' də

Qeyd edildiyi kimi, Python 3.0 + da istifadə edə bilərsiniz

super().__init__()

zənginizi qısa bir müddətdə etmək və valideyn və ya sinif adları üçün əlverişli olan istinadları tələb etmir. Yalnız Python 2.7 və ya daha aşağıda əlavə etmək istərdim ki, self.__class__ adını yazaraq self.__class__ adını nəzərə almadan bu davranışı əldə edə bilərsiniz self.__class__ yerinə sinif adı, yəni.

 super(self.__class__, self).__init__() 

self.__class__ , self.__class__ miras qalan hər hansı bir sinif üçün super çağırışları self.__class__ , self.__class__ bir uşağın sinfi self.__class__ bilər. Məsələn:

 class Polygon(object): def __init__(self, id): self.id = id class Rectangle(Polygon): def __init__(self, id, width, height): super(self.__class__, self).__init__(id) self.shape = (width, height) class Square(Rectangle): pass 

Burada Rectangle bir alt sinfi olan sinif Square var. Deyək ki, Square üçün ayrı bir konstruktor yazmaq istəmirəm, çünki Rectangle üçün konstruktor kifayət qədər yaxşıdır, amma nədənsə bir kvadrat tətbiq etmək istəyirəm ki, başqa bir metoddan istifadə edə bilərəm.

Mən mSquare = Square('a', 10,10) ilə Square yaratdığımda, Python, Rectangle üçün konstruktor çağırır, çünki mən mSquare = Square('a', 10,10) öz konstruktor vermədim. Lakin, Rectangle konstruktorunda super(self.__class__,self) superklassi mSquare-dən mSquare , beləliklə, Rectangle üçün konstruktor çağırır. @S_C tərəfindən qeyd edildiyi kimi, bu sonsuz bir döngədir. Bu halda, super(...).__init__() çalıştırdığımda super(...).__init__() , Rectangle üçün konstruktor çağırıram, amma hər hansı bir argümanı verməmiş olduğundan səhv mesajı alıram.

224
08 окт. AnjoMan tərəfindən oktyabrın 08-də verilən cavab 2013-10-08 23:08 '13 at 23:08 2013-10-08 23:08

Super heç bir yan təsiri yoxdur

 Base = ChildB Base() 

gözlənildiyi kimi işləyir

 Base = ChildA Base() 

sonsuz recursiona düşür.

75
28 нояб. Cavab SC 28 noyabrda verilir. 2012-11-28 02:26 '12, saat 2:26 'da saat 2012-11-28 02:26

Yalnız bir baş ... Python 2.7 ilə, və inanıram ki, super() versiyası 2.2-də tətbiq edildikdən sonra valideynlərdən birinin nəhayət miras aldığı sinifdən devraldıqda super() ( yeni stil sinfləri ).

Şəxsən, python 2.7 BaseClassName.__init__(self, args) mən super() istifadə etmək üstünlüyünü qazanana qədər BaseClassName.__init__(self, args) istifadə etməyə davam edəcəyəm.

68
25 мая '12 в 20:52 2012-05-25 20:52 Cavab rgenito 25 may '12 saat 20:52 'da verilir 2012-05-25 20:52

Həqiqətən deyil. super() metodları çağırmaq üçün növbəti sinfi MRO-da (metod həlli metodundan istifadə etməklə istifadə olunan cls.__mro__ ) cls.__mro__ . Yalnız __init__ bazasını axtararaq, __init__ əsasını __init__ . Bu baş verdiyi kimi, MRO tam bir elementə - bazaya malikdir. Beləliklə, siz eyni şeyi edirsiniz, amma super() ilə daha yaxşı (xüsusilə də birdən çox miras ilə sona çatarsanız).

47
23 февр. Devin Jeanpierre tərəfindən 23 Fevralda verilən cavab 2009-02-23 03:34 '09 at 3:34 am 2009-02-23 03:34

Əsas fərq ChildA.__init__ Base.__init__ , ChildB.__init__ hər hansı bir sinfində ChildB self əcdadlarının xəttində ChildB ata ChildB (gözləniləndən fərqli ola bilər).

Bir çox mirasdan istifadə edən ClassC əlavə ClassC :

 class Mixin(Base): def __init__(self): print "Mixin stuff" super(Mixin, self).__init__() class ChildC(ChildB, Mixin): # Mixin is now between ChildB and Base pass ChildC() help(ChildC) # shows that the the Method Resolution Order is ChildC->ChildB->Mixin->Base 

ChildB ChildC nümunələri üçün Base artıq valideyn deyil . İndi uşaq super(ChildB, self) Mixin bir nümunəsidirsə ChildC .

Siz ChildBBase arasında ChildB əlavə Mixin . Və super() ilə istifadə edə bilərsiniz

Beləliklə, siz çoxlu miras bölüşdürmə ssenarisində istifadə edə biləcəyiniz üçün dərslərinizi inkişaf etdirdiyiniz təqdirdə, sübut istifadə edirsiniz, çünki atanın kimin vaxtında işləməyini həqiqətən bilmirsiniz.

Super superpostpycon 2015 sayılır , müşayiət edən video onu çox yaxşı izah edir.

23
21 сент. Cavab ezerulm 21 sep tərəfindən verilir . 2015-09-21 09:41 '15 at 9:41 pm 2015-09-21 09:41

dair digər suallar və ya sual