2012-01-13 10 views
23

Sono una persona di Java che ha appena iniziato ad imparare Python. Prendete questo esempio:Ereditarietà degli attributi in python usando __init__

class Person(): 
    def __init__(self, name, phone): 
     self.name = name 
     self.phone = phone 

class Teenager(Person): 
    def __init__(self, name, phone, website): 
     self.name=name 
     self.phone=phone 
     self.website=website 

Sono sicuro che ci sono un sacco di codice ridondante (lo so in Java, ci sono un sacco di licenziamenti per il bit di codice di cui sopra).

Quali parti sono ridondanti rispetto a quali attributi sono già stati ereditati dalla classe padre?

risposta

29

Quando si scrive la funzione __init__ per una classe in python, è necessario chiamare sempre la funzione __init__ della sua superclasse. Possiamo usare questo per passare gli attributi rilevanti direttamente alla superclasse, in modo che il codice sarebbe simile a questa:

class Person(object): 
    def __init__(self, name, phone): 
     self.name = name 
     self.phone = phone 
class Teenager(Person): 
    def __init__(self, name, phone, website): 
     Person.__init__(self, name, phone) 
     self.website=website 

Come altri hanno fatto notare, è possibile sostituire la linea

Person.__init__(self, name, phone) 

con

super(Teenager, self).__init__(name, phone) 

e il codice farà la stessa cosa. Questo perché in python instance.method(args) è solo una scorciatoia per Class.method(instance, args). Se si desidera utilizzare super è necessario assicurarsi di specificare object come classe base per Person come ho fatto nel mio codice.

Il python documentation ha ulteriori informazioni su come utilizzare la parola chiave super. La cosa importante in questo caso è che si dice a Python di cercare il metodo di __init__ in una superclasse di self che non è Teenager

+2

Nota: se stai usando Python 2.x, devi esplicitamente elencare 'object' come una classe base di' Person' per usare 'super()'. Altrimenti, devi usare il modulo 'Person .__ init__'. – chepner

+0

@chepner puoi fornire un riferimento per questo? Non riesco a trovarne uno – murgatroid99

+0

http://docs.python.org/library/functions.html#super indica che super() è supportato solo su classi di nuovo stile, che in Python 2.x sono quelle che ereditano da 'object' – chepner

5

attributi in Python non sono ereditate quando vengono definiti nella funzione di costruzione e genitore costruttore della classe non si chiama , a meno che non si fa tutto questo manualmente:

class Person(): 
    def __init__(self, name, phone): 
     self.name = name 
     self.phone = phone 
class Teenager(Person): 
    def_init_(self, name, phone, website): 
     Person.__init__(self, name, phone) # Call parent class constructor. 
     self.website=website 

più su di esso qui: http://docs.python.org/tutorial/classes.html#inheritance

1

__init__, a differenza di un costruttore Java, non si chiama automaticamente per ogni classe nella gerarchia di ereditarietà - è necessario t o fai da te

Inoltre, tutte le gerarchie degli oggetti devono essere rootate a object (tranne in casi speciali).

Il codice dovrebbe leggere:

class Person(object): 
    def __init__(self, name, phone): 
     self.name = name 
     self.phone = phone 
class Teenager(Person): 
    def_init_(self, name, phone, website): 
     super(Teenager, self).__init__(name, phone) 
     self.website=website 

super crea un delegato per il suo secondo argomento (self), che chiamerà la funzione successiva nella lista delle funzioni di chiamare per ogni nome (l ' "ordine di risoluzione metodo "). Questo non è esattamente come chiamare il metodo della superclasse, come accade in Java.

È inoltre possibile scrivere super(type(self), self).__init__(name, phone), ma se si eredita ulteriormente da questa classe, type(self) potrebbe non essere Teenager e si potrebbe avere una ricorsione infinita. Questa è una conseguenza pratica del fatto che si sta lavorando con un oggetto delegato con una differenza MRO, anziché chiamare direttamente un costruttore di superclasse.

11

modo un po 'più pulito che mi piace fare questo:

class Teenager(Person): 
     def __init__(self, *args, **kwargs): 
      self.website=kwargs.pop('website') 
      super(Teenager, self).__init__(*args, **kwargs) 

non fa molta differenza, in questo caso, ma quando si ha un __init__ con una tonnellata di argomenti, rende la vita più facile.

+0

Aumentato per l'uso di * args e ** kwargs (... efficiente nel caso di numerosi argomenti). –

Problemi correlati