Come restituire un valore da __init__ in Python?


102

Ho una classe con una __init__funzione.

Come posso restituire un valore intero da questa funzione quando viene creato un oggetto?

Ho scritto un programma, dove __init__viene eseguita l'analisi della riga di comando e ho bisogno di impostare un valore. Va bene impostarlo nella variabile globale e usarlo in altre funzioni membro? In caso affermativo, come farlo? Finora, ho dichiarato una variabile al di fuori della classe. e impostandola una funzione non si riflette in un'altra funzione ??


8
Se stavi pensando di restituire un codice di errore, solleva invece un'eccezione.
JoeG

1
Rimuovi il tuo commento e aggiorna la tua domanda. Sei tu la domanda. È la tua domanda. Risolvi la domanda per mostrare correttamente qual è il tuo vero problema. Stai abusando __init__; possiamo aiutarti se descrivi ciò che stai veramente cercando di realizzare.
S.Lott

Risposte:


117

__init__è necessario restituire Nessuno. Non puoi (o almeno non dovresti) restituire qualcos'altro.

Prova a fare quello che vuoi per restituire una variabile di istanza (o una funzione).

>>> class Foo:
...     def __init__(self):
...         return 42
... 
>>> foo = Foo()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: __init__() should return None

24
+1: non puoi restituire qualcos'altro. Non ha alcun senso.
S.Lott

72
init non restituisce l'oggetto appena creato - come visto in TypeError, è necessario restituire None, giusto? L'oggetto appena creato viene restituito da new , init imposta solo alcuni dei suoi attributi. Ma sì, come hai detto, cambiare init , o new , per restituire qualcos'altro non ha davvero senso.
weronika

Dov'è newqui? È newimplicito in Python? Presumo che la semantica di Python fosse diversa da Java e dagli altri linguaggi che usano questa parola.
cs95

1
@Shiva AFAIK, per new weronika significava __new __ (self) non la semantica java generale.
Harsh Daftary

2
Solo perché non può essere fatto non significa che non abbia senso. Ad esempio, sarebbe utile passare i dati dalla super().__init__classe derivata senza doverli inoltrare tramite una variabile di istanza.
cz

123

Perché dovresti farlo?

Se vuoi restituire qualche altro oggetto quando viene chiamata una classe, usa il __new__()metodo:

class MyClass(object):
    def __init__(self):
        print "never called in this case"
    def __new__(cls):
        return 42

obj = MyClass()
print obj

9
Sì, il nuovo è il modo giusto per restituire qualcosa di diverso da un'istanza di classe quando si utilizza una classe ... Mi chiedo solo: c'è qualche motivo per cui potresti volerlo FARE?
weronika

33
@weronika Un'idea: in qualsiasi situazione in cui normalmente useresti una fabbrica, ma hai qualche motivo per voler presentare un'interfaccia che assomigli a una normale istanza di classe. Esempio: quando si aggiungono nuovi parametri opzionali alla propria classe __init__, ci si rende conto che in realtà, per fornire la flessibilità desiderata, è necessaria una class factory che restituisca istanze di sottoclassi specializzate. Ma gli utenti della tua libreria stanno già utilizzando la tua API esistente. Per conservarlo, esegui l'override __new__per restituire istanze delle tue sottoclassi specializzate.
Mark Amery

10
Se vuoi vedere un esempio di ciò che ha detto Mark Amery, controlla il codice sorgente del datetimemodulo dalla Standard Library. Si usa __new__esattamente in questo modo.
Zearin

Inoltre, se qualcuno vuole farlo, assicurati di ereditare da object altrimenti non funzionerà.
Mino_e

Penso che a questo punto, solo usare una funzione normale abbia più senso. Potrebbe essere un po 'estraneo alle persone della dimensione Java (funzioni non nelle classi? Eresia!) Ma è pitonico. (Inoltre puoi assegnare proprietà a funzioni come funtionName.val = .. che è un po 'selvaggio ma funziona)
Shayne

37

Dalla documentazione di__init__ :

Come vincolo speciale per i costruttori, non può essere restituito alcun valore; così facendo, verrà sollevata un'eccezione TypeError in fase di esecuzione.

Come prova, questo codice:

class Foo(object):
    def __init__(self):
        return 2

f = Foo()

Fornisce questo errore:

Traceback (most recent call last):
  File "test_init.py", line 5, in <module>
    f = Foo()
TypeError: __init__() should return None, not 'int'

17

L'utilizzo di esempio dell'argomento in questione può essere come:

class SampleObject(object):

    def __new__(cls, item):
        if cls.IsValid(item):
            return super(SampleObject, cls).__new__(cls)
        else:
            return None

    def __init__(self, item):
        self.InitData(item) #large amount of data and very complex calculations

...

ValidObjects = []
for i in data:
    item = SampleObject(i)
    if item:             # in case the i data is valid for the sample object
        ValidObjects.append(item)

Non ho abbastanza reputazione quindi non posso scrivere un commento, è pazzesco! Vorrei poterlo postare come commento a Weronika


3
Questo solleverà un'eccezione NameError: selfnon è definito in__new__(cls, Item)
Hart Simha

15

Il __init__metodo, come altri metodi e funzioni, restituisce None per impostazione predefinita in assenza di un'istruzione return, quindi puoi scriverlo come uno di questi:

class Foo:
    def __init__(self):
        self.value=42

class Bar:
    def __init__(self):
        self.value=42
        return None

Ma, ovviamente, l'aggiunta di return Nonenon ti fa guadagnare nulla.

Non sono sicuro di cosa stai cercando, ma potresti essere interessato a uno di questi:

class Foo:
    def __init__(self):
        self.value=42
    def __str__(self):
        return str(self.value)

f=Foo()
print f.value
print f

stampe:

42
42

ohh ... posso accedere alla variabile membro fuori dalla classe? Allora questo dovrebbe risolvere il mio problema .... grazie
webminal.org

@lakshmipathi, Sì, le variabili di istanza come questa sono pubbliche.
quamrana

Come oneliner per ottenere qualcosa di prezioso restituito dopo l'inizio di un corso:f = Foo().value
JLT

@ JLT Sì, lo fai sempre, ma ciò non significa che venga restituito qualcosa __init__.
quamrana

7

__init__non restituisce nulla e deve sempre tornare None.


4

Puoi semplicemente impostarlo su una variabile di classe e leggerlo dal programma principale:

class Foo:
    def __init__(self):
        #Do your stuff here
        self.returncode = 42
bar = Foo()
baz = bar.returncode

2

Volevo solo aggiungere, puoi restituire le classi in __init__

@property
def failureException(self):
    class MyCustomException(AssertionError):
        def __init__(self_, *args, **kwargs):
            *** Your code here ***
            return super().__init__(*args, **kwargs)

    MyCustomException.__name__ = AssertionError.__name__
    return MyCustomException

Il metodo sopra ti aiuta a implementare un'azione specifica su un'eccezione nel tuo test


2
super().__init__sta tornando None, quindi stai tornando None, il che va bene, ma ridondante.
cz

2

init () restituisce nessun valore risolto perfettamente

class Solve:
def __init__(self,w,d):
    self.value=w
    self.unit=d
def __str__(self):
    return str("my speed is "+str(self.value)+" "+str(self.unit))
ob=Solve(21,'kmh')
print (ob)

uscita: la mia velocità è di 21 kmh


-2

Bene, se non ti interessa più l'istanza dell'oggetto ... puoi semplicemente sostituirla!

class MuaHaHa():
def __init__(self, ret):
    self=ret

print MuaHaHa('foo')=='foo'

2
Ciò cambia solo ciò che viene assegnato al nome selfall'interno di quel costruttore.
Ondrej K.
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.