699 votes

L'utilisation de Python de __new__ et __init__?

Je suis juste essayer de rationaliser l'une de mes classes et ont introduit certaines fonctionnalités dans le même style que le poids mouche modèle de conception.

Cependant, je suis un peu confus quant à pourquoi __init__ est toujours appelée après l' __new__. Je ne m'y attendais pas. Quelqu'un peut me dire pourquoi ce qui se passe et comment je mettre en œuvre cette fonctionnalité, sinon? (en plus de mettre sur la mise en œuvre dans l' __new__ qui se sent tout à fait hacky).

Voici un exemple:

class A(object):
    _dict = dict()

    def __new__(cls):
    	if 'key' in A._dict:
    		print "EXISTS"
    		return A._dict['key']
    	else:
    		print "NEW"
    		return super(A, cls).__new__(cls)

    def __init__(self):
    	print "INIT"
    	A._dict['key'] = self
    	print ""

a1 = A()
a2 = A()
a3 = A()

Sorties:

NEW
INIT

EXISTS
INIT

EXISTS
INIT

Pourquoi?

728voto

mpeterson Points 551

Utilisation __new__ lorsque vous avez besoin de contrôler la création d'une nouvelle instance. Utilisation __init__ quand vous en avez besoin pour le contrôle de l'initialisation d'une nouvelle instance.

__new__ est la première étape de création de l'instance. Il est appelé en premier, et est responsable pour le retour d'une nouvelle instance de votre classe. En revanche, __init__ ne retourne rien, c'est seulement responsable de l'initialisation de la exemple après avoir été créée.

En général, vous ne devriez pas avoir à remplacer __new__ sauf si vous êtes sous-classement d'un type immuable str, int, unicode ou tuple.

De: http://mail.python.org/pipermail/tutor/2008-April/061426.html

Vous devriez penser que ce que vous essayez de faire est généralement fait avec une Usine et que c'est la meilleure façon de le faire. À l'aide de __new__ n'est pas une bonne solution propre, veuillez envisager l'utilisation d'une usine. Vous avez ici un bon exemple de l'usine.

204voto

vartec Points 53382

__new__ est statique méthode de classe, tandis que d' __init__ est la méthode d'instance. __new__ a pour créer l'instance de la première, de sorte __init__ pouvez l'initialiser. Notez que __init__ faut self comme paramètre. Jusqu'à la création de l'instance il n'y a pas d' self.

Maintenant, j'imagine que vous êtes en train d'implémenter le pattern singleton en Python. Il ya quelques façons de le faire.

Aussi, depuis la version 2.6 de Python, vous pouvez utiliser la classe décorateurs.

def singleton(cls):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls()
        return instances[cls]
    return getinstance

@singleton
class MyClass:
  ...

181voto

Ben Points 22160

Dans la plupart bien connus des langages à objets, une expression comme SomeClass(arg1, arg2) attribuera une nouvelle instance, l'initialisation de l'instance attributs, puis le retourner.

Dans la plupart bien connus des langages à objets, l'initialisation de l'instance attributs" partie peut être personnalisé pour chaque classe par la définition d'un constructeur, qui est fondamentalement juste un bloc de code qui fonctionne sur la nouvelle instance (à l'aide des arguments fournis par le constructeur de l'expression) pour mettre en place quelles que soient les conditions initiales sont souhaitées. En Python, ce qui correspond à la classe' __init__ méthode.

Python __new__ n'est rien de plus et rien de moins que les autres par classe de personnalisation de la "allouer une nouvelle instance de la partie". Bien sûr, cela vous permet de faire des choses inhabituelles, comme un retour à une instance existante plutôt que d'attribuer un nouveau. Donc en Python, on ne pense pas vraiment que de cette partie comme impliquant nécessairement la répartition; tout ce que nous demandons, c'est qu' __new__ vient avec un exemple de quelque part.

Mais il est encore seulement la moitié du travail, et il n'y a aucun moyen pour le Python système de savoir que, parfois, vous voulez exécuter l'autre moitié de l'emploi (__init__) par la suite et parfois vous n'en avez pas. Si vous voulez que le comportement, vous avez le dire explicitement.

Souvent, vous pouvez restructurer donc, vous avez seulement besoin d' __new__, ou si vous n'avez pas besoin d' __new__, ou d' __init__ se comporte différemment sur un déjà-initialisation de l'objet. Mais si vous voulez vraiment, Python n'effectivement vous permettre de redéfinir "le travail", de sorte qu' SomeClass(arg1, arg2) n'est pas forcément __new__ suivie par __init__. Pour ce faire, vous devez créer une métaclasse, et de définir ses __call__ méthode.

Une métaclasse est juste la classe d'une classe. Et une classe' __call__ méthode contrôle ce qui se produit lorsque vous appelez les instances de la classe. Ainsi, une métaclasse' __call__ méthode contrôle ce qui se produit lorsque vous appelez une classe; c'est à dire qu'il permet de redéfinir l'instance-mécanisme de création du début à la fin. C'est le niveau à partir duquel vous pouvez plus élégamment mettre en œuvre entièrement non-standard de la création de l'instance de processus tels que le pattern singleton. En fait, avec moins de 10 lignes de code que vous pouvez mettre en œuvre un Singleton métaclasse qui, ensuite, n'a même pas besoin de vous futz avec __new__ à tous, et peut tourner tout autrement-classe normale dans un singleton par le simple ajout d' __metaclass__ = Singleton!

class Singleton(type):
    def __init__(self, *args, **kwargs):
        super(Singleton, self).__init__(*args, **kwargs)
        self.__instance = None
    def __call__(self, *args, **kwargs):
        if self.__instance is None:
            self.__instance = super(Singleton, self).__call__(*args, **kwargs)
        return self.__instance

Cependant, c'est probablement plus profond de la magie que ce qui est vraiment garanti pour cette situation!

32voto

tgray Points 4002

Pour citer la documentation:

Typique des implémentations de créer une nouvelle instance de la classe en invoquant la superclasse __new__() la méthode à l'aide de "super(currentclass, cls).__new__(cls[, ...])"avec les arguments appropriés, puis la modification de la nouvelle instance que nécessaire avant de le retourner.

...

Si __new__() ne retourne pas une instance de cls, puis le nouveau l'instance de __init__() la méthode ne sera pas invoquée.

__new__() est destiné principalement à permettre aux sous-classes immuables types (comme int, str, ou tuple) pour personnaliser la création de l'instance.

10voto

PMN Points 81

Je pense que la réponse simple à cette question est que, si retourne une valeur qui est du même type que la classe, la de la fonction, sinon il ne sera pas. Dans ce cas, votre code renvoie `` qui est la même classe que `` , alors `` sera exécutée.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X