2010-01-26 11 views
7

Toute idée s'il y a un moyen de rendre le code suivant pour travaillerchangement instance de classe à l'intérieur d'une méthode d'instance

class Test(object): 

    def __init__(self, var): 
     self.var = var 

    def changeme(self): 
     self = Test(3) 

t = Test(1) 
assert t.var == 1 
t.changeme() 
assert t.var == 3 

est quelque chose comme à une utilisation sûre ci-dessous pour des objets plus complexes (comme les modèles de django, à chaud permuter l'entrée db à laquelle l'instance fait référence)

class Test(object): 

    def __init__(self, var): 
     self.var = var 

    def changeme(self): 
     new_instance = Test(3) 
     self.__dict__ = new_instance.__dict__ 

t = Test(1) 
assert t.var == 1 
t.changeme() 
assert t.var == 3 
+2

Pourquoi? Vous voulez clairement une nouvelle instance, pourquoi ne pas créer une nouvelle instance et jeter celle-ci? Expliquez l'usecase, s'il vous plaît. –

Répondre

7

self = Test(3) renigne le nom local self, sans effets externes observables.

Attribution self.__dict__ (à moins que vous parlez des cas avec __slots__ ou des classes avec métaclasses non trivial) est généralement OK, et est donc self.__init__(3) de ré-initialiser l'instance. Cependant je préférerais avoir une méthode spécifique self.restart(3) qui sait il est appelé sur une instance déjà-initialisée et fait tout ce qui est nécessaire pour répondre à ce cas spécifique et inhabituel.

+0

Les métaclasses modèles de Django sont ... malpropres. Je ne serais pas surpris si essayer de réaffecter 'self .__ dict__' explosait spectaculairement. –

+0

@Ignacio, avec "metaclasses non-trivial" en jeu (ou '__slots__', etc), vous pouvez utiliser une boucle de' getattr'/'setattr' à la place. L'avantage de l'écriture de la méthode 'restart' que je préconise est que vous y isoliez les ajustements (le cas échéant) nécessaires pour supporter différents cas, des objets normaux aux objets avec des métaclasses désordonnées et ainsi de suite. –

3

Non, et non.

Cela dit, vous pouvez changer la classe , mais ne le faites pas non plus.

2

L'ancien code fonctionne, sauf qu'il ne fera pas grand-chose, vu qu'il remplace juste l'objet nommé 'self' dans la portée de changeme(). Les noms Python ne sont pas verrouillés sur les valeurs, ils sont toujours relatifs à leur portée ou à leur espace de noms.

Pour faire ce que vous voulez, vous aurez besoin d'avoir accès à un nom en dehors de la classe, que vous pouvez affecter à l'intérieur il:

class Test: 
    def changeme(self): 
    global myclass 
    myclass = Test(3) 

myclass = Test(2) 
myclass.changeme() 
print myclass # 3 

Cela remplace fondamentalement juste le nom « maclasse » au point à la nouvelle instance. Il ne "écrase" pas la première instance comme vous pourriez le penser. L'ancienne instance vit toujours et sera collectée à moins d'être référencée ailleurs.