2010-03-22 14 views
68

Ho una classe con una funzione __init__.Come restituire un valore da __init__ in Python?

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

Ho scritto un programma, dove __init__ esegue l'analisi della riga di comando e ho bisogno di avere qualche valore impostato. È OK impostarlo nella variabile globale e usarlo in altre funzioni membro? Se sì, come farlo? Finora, ho dichiarato una variabile al di fuori della classe. e impostando una funzione non riflette in altre funzioni ??

+6

Se si pensava di restituire un codice di errore, sollevare invece un'eccezione. –

+0

Rimuovi il tuo commento e aggiorna la tua domanda. Possiedi la domanda. È la tua domanda Correggi la domanda per mostrare correttamente qual è il tuo vero problema. Stai abusando di '__init__'; possiamo aiutarti se descrivi cosa stai davvero cercando di realizzare. –

risposta

67

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

Provare a rendere qualsiasi cosa si desideri restituire una variabile di istanza (o 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 
+15

+1: Tu ** non puoi ** restituire qualcos'altro. Non ha alcun senso. –

+63

__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 alcun senso. – weronika

+0

Dov'è 'new' qui? 'New' è implicito in Python? Ho assunto che la semantica di Python fosse diversa da Java e dalle altre lingue che usano questa parola. –

8

__init__ non restituisce nulla e dovrebbe sempre tornare None.

37

Dal documentation of __init__:

As a special constraint on constructors, no value may be returned; doing so will cause a TypeError to be raised at runtime.

Come prova, questo codice:

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

f = Foo() 

dà questo errore:

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

Perché si vuole farlo?

Se si desidera tornare qualche altro oggetto quando una classe viene chiamato, quindi utilizzare il metodo __new__():

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

obj = MyClass() 
print obj 
+8

Sì, __new__ è il modo giusto per restituire qualcosa di diverso da un'istanza di classe quando si usa una classe ... Mi stavo solo chiedendo - c'è qualche ragione per cui potresti volerlo fare davvero? – weronika

+22

@weronika Un'idea: in ogni situazione in cui normalmente utilizzi una fabbrica, ma hai qualche motivo per voler presentare un'interfaccia che assomigli a un'istanza di classe normale. Esempio: quando aggiungi alcuni nuovi parametri opzionali nella '__init__' della tua classe, ti rendi conto che in realtà, per fornire la flessibilità che desideri, hai bisogno di una classe factory che restituisca istanze di sottoclassi specializzate. Ma gli utenti della tua biblioteca stanno già utilizzando la tua API esistente. Per preservarlo, si ridefinisce '__new__' per restituire le istanze delle sottoclassi specializzate. –

+6

Se vuoi vedere un esempio di ciò che Mark Amery ha detto, controlla il codice sorgente del modulo 'datetime' dalla Libreria standard. Usa '__new__' esattamente in questo modo. – Zearin

12

Il metodo __init__, come altri metodi e funzioni restituisce None di default in assenza di un ritorno dichiarazione, in modo da poter scrivere le cose come uno di questi:

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

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

Ma, naturalmente, aggiungendo il return None non ti comprare nulla.

io non sono sicuro di quello che sono dopo, ma si potrebbe essere interessati a una di queste:

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 
+0

ohh..Posso accedere alla variabile membro fuori dalla classe? Allora questo dovrebbe risolvere il mio problema .... grazie –

+0

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

+0

Come oneliner per ottenere qualcosa di prezioso restituito dopo l'avvio di una classe: 'f = Foo(). Value ' – JLT

13

Sample dell'uso della materia in questione può essere come :

class SampleObject(object) 

    def __new__(cls,Item) 
     if self.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, i è pazzo!Vorrei poter postare come un commento a weronika

+1

Questo solleverà un'eccezione NameError: 'self' non è definito in' __new __ (cls, Item) ' –

2

Volevo solo aggiungere classi, è possibile tornare 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 di cui sopra consente di implementare una specifica azione su un'eccezione nel tuo test

+0

si prega di approfondire questo codice. – nish

Problemi correlati