Costruttori Python e __init__


107

Perché i costruttori sono effettivamente chiamati "costruttori"? Qual è il loro scopo e in cosa differiscono dai metodi di una classe?

Inoltre, può essercene più di uno __init__in una classe? Ho provato quanto segue, qualcuno può spiegare il risultato?

>>> class test:
    def __init__(self):
        print "init 1"
    def __init__(self):
        print "init 2"

>>> s=test()
init 2

Infine, è __init__un operatore di sovraccarico?


41
Tecnicamente, __init__è un inizializzatore . Il costruttore di python è __new__. Python utilizza l'inizializzazione automatica a due fasi - __new__restituisce un oggetto valido ma (di solito) non popolato (vedi boolper un controesempio), che poi lo ha __init__richiamato automaticamente. Ciò evita i problemi che linguaggi come C ++ hanno con oggetti parzialmente costruiti - non ne hai mai uno in Python (sebbene possa essere parzialmente inizializzato). Non avrai quasi mai bisogno di sovrascrivere entrambi __new__e __init__su una classe.
Tim Delaney

2
@TimDelaney: Non sono sicuro di cosa intendi con oggetti parzialmente costruiti in C ++.
Sebastian Mach

11
@phresnel In C ++ il tipo di oggetto è la classe base (non la sottoclasse) mentre si trova nel costruttore della classe base. Non è possibile chiamare un metodo virtuale nel costruttore della classe base e fare in modo che la sottoclasse fornisca l'implementazione. In Java è possibile chiamare un metodo di sottoclasse nel costruttore della classe di base, ma le variabili dei membri della sottoclasse verranno automaticamente inizializzate dopo il costruttore della classe di base (e la chiamata al metodo). Nei linguaggi con inizializzazione a due fasi come Python, puoi tranquillamente chiamare i metodi nell'inizializzatore della classe base e fare in modo che la sottoclasse fornisca (o sovrascriva) il comportamento.
Tim Delaney

@TimDelaney: Ah, grazie per aver chiarito.
Sebastian Mach

4
@TimDelaney. Penso che il tuo commento dovrebbe sostituire la risposta accettata.
flamenco

Risposte:


114

Non esiste un sovraccarico di funzioni in Python, il che significa che non è possibile avere più funzioni con lo stesso nome ma argomenti diversi.

Nel tuo esempio di codice, non stai sovraccaricando __init__() . Quello che succede è che la seconda definizione riassocia il nome __init__al nuovo metodo, rendendo il primo metodo inaccessibile.

Per quanto riguarda la tua domanda generale sui costruttori, Wikipedia è un buon punto di partenza. Per cose specifiche di Python, consiglio vivamente i documenti di Python .


Significa anche che il file sorgente viene analizzato (interpretato?) In sequenza? Posso essere sicuro che qualunque funzione che ho definito in seguito sovrascrive quella definita con lo stesso nome in precedenza? :( la mia Q sembra sciocca .. avrei dovuto
saperlo

4
@ 0xc0de: In Python, le definizioni di funzione sono in realtà istruzioni eseguibili e vengono eseguite dall'alto verso il basso, quindi sì.
NPE

1
@ 0xc0de Quello che effettivamente accade è che il corpo della classe viene eseguito nel proprio spazio dei nomi, quello spazio dei nomi viene quindi passato alla metaclasse (tra con il nome e le basi). Le definizioni di funzione quindi creano solo una funzione con il corpo specificato e la assegnano al suo nome. L'ultimo compito __init__sarà quello che finisce in classe.
Skyking

64

Perché i costruttori sono effettivamente chiamati "costruttori"?

Il costruttore (denominato __new__) crea e restituisce una nuova istanza della classe. Quindi il C.__new__metodo di classe è il costruttore per la classe C.

Il C.__init__metodo dell'istanza viene chiamato su un'istanza specifica, dopo che è stata creata, per inizializzarla prima di essere ritrasmessa al chiamante. Quindi quel metodo è l' inizializzatore per nuove istanze di C.

In che modo sono diversi dai metodi in una classe?

Come affermato nella documentazione ufficiale, __init__ viene richiamato dopo la creazione dell'istanza . Altri metodi non ricevono questo trattamento.

Qual è il loro scopo?

Lo scopo del costruttore C.__new__è definire il comportamento personalizzato durante la costruzione di una nuova Cistanza.

Lo scopo dell'inizializzatore C.__init__è definire l'inizializzazione personalizzata di ogni istanza di Cdopo che è stata creata.

Ad esempio Python ti permette di fare:

class Test(object):
    pass

t = Test()

t.x = 10   # here you're building your object t
print t.x

Ma se vuoi che ogni istanza di Testabbia un attributo xuguale a 10, puoi inserire quel codice all'interno __init__:

class Test(object):
    def __init__(self):
        self.x = 10

t = Test()
print t.x

Ogni metodo di istanza (un metodo chiamato su un'istanza specifica di una classe) riceve l'istanza come primo argomento. Questo argomento è convenzionalmente denominato self.

I metodi di classe, come il costruttore __new__, ricevono invece la classe come primo argomento.

Ora, se desideri valori personalizzati per l' xattributo, tutto ciò che devi fare è passare quel valore come argomento a __init__:

class Test(object):
    def __init__(self, x):
        self.x = x

t = Test(10)
print t.x
z = Test(20)
print t.x

Spero che questo ti aiuti a chiarire alcuni dubbi e, poiché hai già ricevuto buone risposte alle altre domande, mi fermo qui :)


9

Le classi sono semplicemente schemi da cui creare oggetti. Il costruttore è un codice che viene eseguito ogni volta che crei un oggetto. Quindi non ha senso avere due costruttori. Quello che succede è che il secondo sovrascrive il primo.

Quello per cui li usi in genere è creare variabili per quell'oggetto in questo modo:

>>> class testing:
...     def __init__(self, init_value):
...         self.some_value = init_value

Quindi quello che potresti fare allora è creare un oggetto da questa classe come questo:

>>> testobject = testing(5)

L'oggetto test avrà quindi un oggetto chiamato some_valueche in questo esempio sarà 5.

>>> testobject.some_value
5

Ma non è necessario impostare un valore per ogni oggetto come ho fatto nel mio campione. Puoi anche fare così:

>>> class testing:
...     def __init__(self):
...         self.some_value = 5

quindi il valore di some_value sarà 5 e non è necessario impostarlo quando si crea l'oggetto.

>>> testobject = testing()
>>> testobject.some_value
5

il >>> e ... nel mio campione non è quello che scrivi. È come apparirebbe in pyshell ...


Nessun problema, sono felice che ti abbia aiutato :)
Niclas Nilsson

1

i coonstructors vengono chiamati automaticamente quando si crea un nuovo oggetto, in tal modo "costruendo" l'oggetto. Il motivo per cui puoi avere più di un init è perché i nomi sono solo riferimenti in python e ti è permesso cambiare ciò a cui ogni variabile fa riferimento ogni volta che vuoi (quindi digitazione dinamica)

def func(): #now func refers to an empty funcion
    pass
...
func=5      #now func refers to the number 5
def func():
    print "something"    #now func refers to a different function

nella definizione della tua classe, mantiene solo quella successiva


0

Non esiste la nozione di sovraccarico del metodo in Python. Ma puoi ottenere un effetto simile specificando argomenti facoltativi e parole chiave

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.