2010-01-26 14 views
7

Alguna idea de si hay una manera de hacer el siguiente código para trabajarCambio instancia de clase dentro de un método de instancia

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 

es algo como el siguiente seguro de usar para objetos más complejos (como modelos de Django, a caliente intercambie la entrada de db a la que hace referencia la instancia)

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

¿Por qué? Claramente quieres una nueva instancia, ¿por qué no crear una nueva instancia y descartarla? Explique el caso de uso, por favor. –

Respuesta

7

self = Test(3) está volviendo a enlazar el nombre local self, sin efectos observables externamente.

Asignación self.__dict__ (a menos que estés hablando de casos con __slots__ o de clases con metaclases no triviales) es por lo general bien, y también lo es self.__init__(3) para reiniciar la instancia. Sin embargo, preferiría tener un método específico self.restart(3) que conoce se está llamando en una instancia ya iniciada y hace lo que sea necesario para atender ese caso específico e inusual.

+0

Las metaclases del modelo de Django son ... desordenadas. No me sorprendería si al intentar reasignar 'self .__ dict__' explotara espectacularmente. –

+0

@Ignacio, con "metaclases no triviales" en juego (o '__slots__', etc.), es posible que desee utilizar un bucle de' getattr'/'setattr' en su lugar. La ventaja de escribir el método de "reinicio" que defiendo es que aísles allí los ajustes (si corresponde) necesarios para admitir varios casos, desde objetos normales hasta objetos con metaclases desordenadas y demás. –

3

No, y no.

Dicho esto, se puede cambiar la clase, pero no hacer que tampoco.

2

El código anterior funciona, excepto que no hará mucho, ya que simplemente reemplaza el objeto llamado 'self' dentro del ámbito de changeme(). Los nombres de Python no están bloqueados a valores, siempre están relacionados con su alcance o espacio de nombres.

Para hacer lo que quiera que había necesidad de tener acceso a un nombre fuera de la clase, lo que podría asignar a partir de dentro de ella:

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

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

Esto, básicamente, sólo sobrescribe el nombre 'miclase' para señalar a la nueva instancia. No "sobrescribe" la primera instancia como podría pensar. La instancia anterior aún vive, y será recogida de basura a menos que se haga referencia en otro lugar.

Cuestiones relacionadas