Comment renvoyer une valeur de __init__ en Python?


102

J'ai une classe avec une __init__fonction.

Comment puis-je renvoyer une valeur entière à partir de cette fonction lorsqu'un objet est créé?

J'ai écrit un programme, d'où l' __init__analyse de la ligne de commande et j'ai besoin d'un jeu de valeurs. Est-il correct de le définir dans une variable globale et de l'utiliser dans d'autres fonctions membres? Si oui, comment faire cela? Jusqu'à présent, j'ai déclaré une variable hors classe. et la définition d'une fonction ne se reflète pas dans une autre fonction ??


8
Si vous envisagez de renvoyer un code d'erreur, générez plutôt une exception.
JoeG

1
Veuillez supprimer votre commentaire et mettre à jour votre question. Vous possédez la question. C'est ta question. Veuillez corriger la question pour montrer correctement quel est votre véritable problème. Vous abusez __init__; nous pouvons vous aider si vous décrivez ce que vous essayez vraiment d'accomplir.
S.Lott

Réponses:


117

__init__est nécessaire pour renvoyer Aucun. Vous ne pouvez pas (ou du moins ne devriez pas) retourner quelque chose d'autre.

Essayez de créer ce que vous voulez pour renvoyer une variable d'instance (ou une fonction).

>>> 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: Vous ne pouvez pas retourner autre chose. Cela n'a aucun sens.
S.Lott

72
init ne renvoie pas l'objet nouvellement créé - comme vu dans TypeError, il est nécessaire de renvoyer None, non? L'objet nouvellement créé est renvoyé par new , init définit simplement certains de ses attributs. Mais oui, comme vous l'avez dit, changer init , ou new , pour retourner quelque chose d'autre n'a vraiment aucun sens.
weronika le

Où est newici? Est-ce newimplicite en Python? J'ai supposé que la sémantique de Python était différente de Java et des autres langages qui utilisent ce mot.
cs95 le

1
@Shiva AFAIK, par new weronika signifiait __new __ (self) pas la sémantique générale de Java.
Harsh Daftary

2
Ce n'est pas parce que cela ne peut pas être fait que cela n'a pas de sens. Il serait, par exemple, agréable de transmettre des données super().__init__à la classe dérivée sans avoir à les relayer via une variable d'instance.
cz

123

Pourquoi voudriez-vous faire ça?

Si vous souhaitez renvoyer un autre objet lorsqu'une classe est appelée, utilisez la __new__()méthode:

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

obj = MyClass()
print obj

9
Ouais, nouveau est la bonne façon de renvoyer autre chose qu'une instance de classe lors de l'utilisation d'une classe ... Je me demande juste - y a-t-il une raison pour laquelle vous pourriez vraiment vouloir faire cela?
weronika le

33
@weronika Une idée: dans toute situation où vous utiliseriez normalement une fabrique, mais vous avez des raisons de vouloir présenter une interface qui ressemble à une instanciation de classe normale. Exemple: lorsque vous ajoutez de nouveaux paramètres optionnels dans votre classe __init__, vous vous rendez compte qu'en réalité, pour fournir la flexibilité que vous souhaitez, vous avez besoin d'une fabrique de classes qui renvoie des instances de sous-classes spécialisées. Mais les utilisateurs de votre bibliothèque utilisent déjà votre API existante. Pour le conserver, vous remplacez __new__pour renvoyer des instances de vos sous-classes spécialisées.
Mark Amery

10
Si vous voulez voir un exemple de ce que Mark Amery a dit, consultez le code source du datetimemodule dans la bibliothèque standard. Il utilise __new__exactement de cette façon.
Zearin

Aussi, si quelqu'un veut faire cela, assurez-vous d'hériter de l'objet sinon cela ne fonctionnera pas.
Mino_e

Je pense qu'à ce stade, il est plus logique d'utiliser une fonction régulière. Peut-être un peu étranger aux gens de la dimension Java (ne fonctionne pas dans les classes? Hérésie!) Mais c'est pythonique. (Vous pouvez également attribuer des propriétés aux fonctions comme dans funtionName.val = .. qui est un peu sauvage mais cela fonctionne)
Shayne

37

De la documentation de__init__ :

En tant que contrainte spéciale sur les constructeurs, aucune valeur ne peut être renvoyée; cela entraînera le déclenchement d'une TypeError lors de l'exécution.

Pour preuve, ce code:

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

f = Foo()

Donne cette erreur:

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

17

Exemple d'utilisation de la matière en question peut être comme:

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)

Je n'ai pas assez de réputation donc je ne peux pas écrire de commentaire, c'est fou! J'aimerais pouvoir le poster comme commentaire sur weronika


3
Cela lèvera une NameError: selfn'est pas défini dans__new__(cls, Item)
Hart Simha

15

La __init__méthode, comme les autres méthodes et fonctions, retourne None par défaut en l'absence d'une instruction return, vous pouvez donc l'écrire comme l'une des deux:

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

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

Mais bien sûr, ajouter le return Nonene vous achète rien.

Je ne sais pas trop ce que vous recherchez, mais l'un de ceux-ci pourrait vous intéresser:

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

f=Foo()
print f.value
print f

imprime:

42
42

ohh..Puis-je accéder à la variable membre de la classe? Ensuite, cela devrait résoudre mon problème .... merci
webminal.org

@lakshmipathi, Oui, les variables d'instance comme celle-ci sont publiques.
quamrana

En tant que joueur unique pour obtenir quelque chose de précieux retourné après le début d'un cours:f = Foo().value
JLT

@JLT Oui, vous le faites toujours mais cela ne veut toujours pas dire que quoi que ce soit est retourné __init__.
quamrana


4

Vous pouvez simplement le définir sur une variable de classe et le lire à partir du programme principal:

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

2

Je voulais juste ajouter, vous pouvez renvoyer des classes dans __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

La méthode ci-dessus vous aide à implémenter une action spécifique sur une exception dans votre test


2
super().__init__est de retour None, donc vous revenez None, ce qui est bien, mais redondant.
cz

2

init () ne renvoie aucune valeur parfaitement résolue

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)

sortie: ma vitesse est de 21 kmh


-2

Eh bien, si vous ne vous souciez plus de l'instance d'objet ... vous pouvez simplement la remplacer!

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

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

2
Cela change simplement ce qui est assigné au nom à l' selfintérieur de ce constructeur.
Ondrej K.
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.