2010-01-26 8 views
7

Jede Idee, wenn es ein Weg gibt den folgenden Code zu machenändert Klasseninstanz innerhalb einer Instanzmethode

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 

zu arbeiten, ist so etwas wie die folgenden sicher für komplexere Objekte zu verwenden (wie django Modelle, zu heiß vertauschen Sie den DB-Eintrag, auf den sich die Instanz bezieht)

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

Warum? Sie wollen eindeutig eine neue Instanz, warum nicht nur eine neue Instanz machen und diese eine wegzuwerfen? Erklären Sie bitte den Anwendungsfall. –

Antwort

7

self = Test(3) erneut die Bindung des lokalen Namen self, ohne von außen beobachtbaren Effekte.

zuordnen self.__dict__ (es sei denn, Sie Instanzen reden mit __slots__ oder von Klassen mit nicht-trivialer metaclasses) ist in der Regel in Ordnung, und ist so self.__init__(3), um die Instanz neu zu initialisieren. Allerdings würde ich eine spezifische Methode bevorzugen self.restart(3) die kennt es wird auf einer bereits initialisierten Instanz aufgerufen und tut, was benötigt wird, um für diesen spezifischen und ungewöhnlichen Fall gerecht zu werden.

+0

Djangos Modell metaclasses sind ... chaotisch. Ich wäre nicht überrascht, wenn der Versuch, "self .__ dict__" zuzuweisen, spektakulär explodierte. –

+0

@Ignacio, mit "nicht-trivialen Metaklassen" im Spiel (oder "__slots__', usw.), möchten Sie vielleicht stattdessen eine Schleife von' getattr'/'setattr' verwenden. Der Vorteil des Schreibens der "Neustart" -Methode, die ich befürworte, ist, dass Sie dort die Feinabstimmung (falls vorhanden) isolieren, die benötigt wird, um verschiedene Fälle zu unterstützen, von normalen Objekten zu solchen mit unordentlichen Metaklassen und so weiter. –

3

Nein, und nein.

gesagt haben, dass Sie können dieKlasse ändern, aber nicht tun, entweder.

2

Der frühere Code funktioniert, außer es nicht viel tun, da es nur das ‚Selbst‘ im Rahmen von changeme() benannte Objekt ersetzt. Python-Namen sind nicht auf Werte gesperrt, sie sind immer im Verhältnis zu ihrem Umfang oder Namespace.

zu tun, was Sie möchten, dass Sie den Zugriff auf einen Namen außerhalb der Klasse haben müssen, die Sie von innen zuweisen könnten:

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

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

Dieser im Grunde überschreibt nur den Namen ‚myclass‘ Punkt zu der neuen Instanz. Es "überschreibt" nicht die erste Instanz, wie Sie vielleicht denken. Die alte Instanz lebt noch und wird Müll gesammelt, sofern nicht anderswo verwiesen wird.

Verwandte Themen