2012-05-07 18 views
57

Originariamente volevo chiedere this question, ma poi ho scoperto che era già pensato prima ...Python allungabile con - con super() Python 3 vs Python 2

Googling in giro ho trovato questo esempio di extending configparser. Le seguenti opere con Python 3:

$ python3 
Python 3.2.3rc2 (default, Mar 21 2012, 06:59:51) 
[GCC 4.6.3] on linux2 
>>> from configparser import SafeConfigParser 
>>> class AmritaConfigParser(SafeConfigParser): 
...  def __init_(self): 
...   super().__init__() 
... 
>>> cfg = AmritaConfigParser() 

Ma non con Python 2:

>>> class AmritaConfigParser(SafeConfigParser): 
...  def __init__(self): 
...   super(SafeConfigParser).init() 
... 
>>> cfg = AmritaConfigParser() 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 3, in __init__ 
TypeError: must be type, not classob 

poi ho letto un po 'su Python nuova classe vs. stili vecchia classe (ad es here e ora ho. mi chiedo, non posso fare:

class MyConfigParser(ConfigParser.ConfigParser): 
     def Write(self, fp): 
      """override the module's original write funcition""" 
      .... 
     def MyWrite(self, fp): 
      """Define new function and inherit all others""" 

Ma, non dovrei chiamare init è questo in Python 2 l'equivalente:?

012.351.
class AmritaConfigParser(ConfigParser.SafeConfigParser): 
    #def __init__(self): 
    # super().__init__() # Python3 syntax, or rather, new style class syntax ... 
    # 
    # is this the equivalent of the above ? 
    def __init__(self): 
     ConfigParser.SafeConfigParser.__init__(self) 
+1

Nel tuo esempio non è necessario definire un '__init __()' nella sottoclasse se tutto ciò che fa è chiamare la classe super '__init __()' (in o Python 2 o 3) - invece lascia che i super vengano ereditati. – martineau

+0

Riferimento utile: http://amyboyle.ninja/Python-Inheritance/ –

risposta

99
  • super() (senza argomenti) è stato introdotto in Python 3 (insieme a __class__):

    super() -> same as super(__class__, self) 
    

    in modo che sarebbe l'equivalente di Python 2 per classi di nuovo stile:

    super(CurrentClass, self) 
    
  • per classi vecchio stile è sempre possibile utilizzare:

    class Classname(OldStyleParent): 
        def __init__(self, *args, **kwargs): 
         OldStyleParent.__init__(self, *args, **kwargs) 
    
+1

-1. Questa risposta non ha chiarito nulla per me. In Python 2, 'super (__ class __)' fornisce 'NameError: nome globale '__class__' non è definito', e' super (self .__ class __) 'è errato. Tu * devi * fornire un'istanza come secondo argomento, che suggerirebbe che devi fare 'super (self .__ class__, self)', ma questo è ** sbagliato **. Se 'Class2' eredita da' Class1' e 'Class1' chiama' super (self.__class__, self) .__ init __() ',' Class1' '__init__' quindi * chiamerà * quando istanzia un'istanza di' Class2'. – jpmc26

+0

Per chiarire un punto, ottengo 'TypeError: super() richiede almeno 1 argomento (0 dato)' quando si prova a chiamare 'super (self .__ class __)' in Python 2. (Che non ha molto senso , ma dimostra quante informazioni mancano da questa risposta.) – jpmc26

+2

@ jpmc26: in python2 si ottiene questo errore perché si prova a chiamare '__init __()' senza argomento sul super oggetto non associato (che si ottiene chiamando 'super (self .__ class __) 'con un solo argomento), hai bisogno di un oggetto super associato, quindi dovrebbe funzionare:' super (CurrentClass, self) .__ init __() '. Non usare 'self .__ class__' perché farà sempre riferimento alla classe _same_ quando si chiama un genitore e quindi creerà un ciclo infinito se anche quel genitore fa lo stesso. – mata

28

In un caso di ereditarietà singola (quando si sottoclasse solo una classe), la nuova classe eredita i metodi della classe base. Questo include __init__. Quindi se non lo definisci nella tua classe, otterrai quello dalla base.

Le cose iniziano a complicarsi se si introduce l'ereditarietà multipla (sottoclasse più di una classe alla volta). Questo perché se più di una classe base ha __init__, la tua classe erediterà solo la prima.

In questi casi, si dovrebbe usare davvero super se è possibile, spiegherò perché. Ma non sempre puoi. Il problema è che tutte le classi base devono anche usarlo (e anche le loro classi base - l'intero albero).

Se questo è il caso, allora questo sarà anche funzionano correttamente (in Python 3, ma si poteva rielaborare in Python 2 - ha anche super):

class A: 
    def __init__(self): 
     print('A') 
     super().__init__() 

class B: 
    def __init__(self): 
     print('B') 
     super().__init__() 

class C(A, B): 
    pass 

C() 
#prints: 
#A 
#B 

Si noti come entrambe le classi base usano super anche se non hanno le loro classi base.

Cosa fa super: chiama il metodo dalla prossima classe in MRO (metodo di risoluzione dei problemi). L'MRO per C è: (C, A, B, object). È possibile stampare C.__mro__ per vederlo.

Quindi, C eredita __init__ da A e super in A.__init__ chiamate B.__init__ (B segue A in MRO).

Così facendo nulla in C, si finisce per chiamare entrambi, che è quello che vuoi.

Ora, se non si stesse utilizzando super, si finirebbe per ereditare A.__init__ (come prima) ma questa volta non c'è niente che possa chiamare per te B.__init__.

class A: 
    def __init__(self): 
     print('A') 

class B: 
    def __init__(self): 
     print('B') 

class C(A, B): 
    pass 

C() 
#prints: 
#A 

Per risolvere che è necessario definire C.__init__:

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

Il problema di questo è che in alberi MI più complicate, __init__ metodi di alcune classi può finire per essere chiamato più di una volta, mentre eccellente/MRO garantisce che vengano chiamati solo una volta.

+7

'Nota come entrambe le classi base usano super anche se non hanno le loro classi base. In py3k ogni classe sottoclasse l'oggetto. – akaRem

15

In breve, sono equivalenti. Abbiamo una vista cronologia:

(1) all'inizio, la funzione è simile a questa.

(2) per rendere il codice più astratto (e più portatile). Un metodo comune per ottenere Super-Class è inventato come:

super(<class>, <instance>) 

E funzione init può essere:

class MySubClassBetter(MySuperClass): 
     def __init__(self): 
      super(MySubClassBetter, self).__init__() 

che richiede tuttavia un passaggio esplicito sia la classe e l'istanza rompere il DRY (Do not Ripeti te stesso) regola un po '.

(3) in V3. È più intelligente,

super() 

è sufficiente nella maggior parte dei casi. È possibile fare riferimento a http://www.python.org/dev/peps/pep-3135/

0

Solo per avere un esempio semplice e completo di Python 3, che la maggior parte delle persone sembra utilizzare ora.

class MySuper(object): 
    def __init__(self,a): 
     self.a = a 

class MySub(MySuper): 
    def __init__(self,a,b): 
     self.b = b 
     super().__init__(a) 

my_sub = MySub(42,'chickenman') 
print(my_sub.a) 
print(my_sub.b) 

42 
chickenman