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.