Python Objektinitialisierung Fehler. Oder bin ich Missverständnis, wie die Arbeit Objekte?

StackOverflow https://stackoverflow.com/questions/1534407

  •  20-09-2019
  •  | 
  •  

Frage

  1 import sys
  2 
  3 class dummy(object):
  4     def __init__(self, val):
  5         self.val = val
  6 
  7 class myobj(object):
  8     def __init__(self, resources):
  9         self._resources = resources
 10 
 11 class ext(myobj):
 12     def __init__(self, resources=[]):
 13         #myobj.__init__(self, resources)
 14         self._resources = resources
 15 
 16 one = ext()
 17 one._resources.append(1)
 18 two = ext()
 19 
 20 print one._resources
 21 print two._resources
 22 
 23 sys.exit(0)

Damit wird der Verweis auf die zu one._resources für beide one und two Objekten zugeordnet Objekt drucken. Ich würde denken, dass two würde ein leeres Array sein, da es eindeutig als solche Einstellung ist, wenn es nicht definiert ist, wenn das Objekt erstellen. Uncommenting myobj.__init__(self, resources) tut das Gleiche. Mit super(ext, self).__init__(resources) auch tut das gleiche.

Die einzige Art, wie ich es an der Arbeit bekommen kann, ist, wenn ich die folgende:

two = ext(dummy(2))

Ich sollte nicht manuell einstellen müssen, um den Standardwert, wenn Sie das Objekt erstellen, diese Arbeit zu machen. Vielleicht tue ich. Irgendwelche Gedanken?

Ich habe versucht, dies mit Python 2.5 und 2.6.

War es hilfreich?

Lösung

Sie sollten ändern

def __init__(self, resources=[]):
    self._resources = resources

def __init__(self, resources=None):
    if resources is None:
        resources = []
    self._resources = resources

und alles wird besser sein. Dies ist ein Detail in der Art und Weise Standardargumente behandelt werden, wenn sie wandelbar sind. Es gibt einige weitere Informationen in der Diskussion Abschnitt diese Seite .

Andere Tipps

Ihr Problem ist, dass der Standardwert bei Funktionsdefinition Zeit ausgewertet wird. Dies bedeutet, dass das gleiche Liste Objekt zwischen Instanzen gemeinsam genutzt. Siehe Antwort auf diese Frage für weitere Diskussion.

http://docs.python.org/3.1/tutorial/controlflow. html :

  

Der Standardwert wird nur ausgewertet,   Einmal. Das macht einen Unterschied, wenn die   Standardwert ist ein veränderliches Objekt wie eine   Liste, Wörterbuch oder Instanzen von den meisten   Klassen.

Dies ist ein bekannt Python gotcha .

Sie haben auf den Aufruf einer Funktion / Methode unter Verwendung eines veränderliches Objekt zu vermeiden.

  

Die Objekte, die die Standardwerte bieten nicht zu dem Zeitpunkt erstellt, dass die Funktion / Methode aufgerufen wird, . Sie werden zu dem Zeitpunkt erstellt, dass die Aussage, die die Funktion definiert wird ausgeführt . (Siehe auch die Diskussion unter Standardargumente in Python: zwei einfache Fehler : "Ausdrücke in Standardargumenten berechnet werden, wenn die Funktion definiert ist, nicht, wenn es heißt" )

     

Dieses Verhalten ist nicht eine Warze in der Sprache Python. Es ist wirklich ein Feature, kein Bug. Es gibt Zeiten, wenn Sie wirklich wandelbar Standardargumente verwenden wollen. Eine Sache, die sie (zum Beispiel) tun können, ist eine Liste von Ergebnissen aus früheren Anrufungen behalten, etwas, das sehr praktisch sein kann.

     

Aber für die meisten Programmierer - vor allem Pythonistas Anfang - dieses Verhalten ist eine Gotcha. Also für die meisten Fälle, die wir die folgenden Regeln erlassen.

     
      
  • Sie nie ein veränderbares Objekt verwenden - das ist:. Eine Liste, ein Wörterbuch oder eine Klasseninstanz - als Standardwert eines Arguments
  •   
  • Ignorieren Regel 1 nur, wenn Sie wirklich, wirklich, wirklich wissen, was Sie tun.
  •   
     

So ... wir planen immer Regel # 1 zu folgen. Nun, die Frage ist, wie es zu tun ... wie man Code Funktion f, um das Verhalten zu bekommen, dass wir wollen.

     

Zum Glück ist die Lösung einfach. Die veränderbaren Objekte als Standardwert verwendet werden, durch None ersetzt, und dann werden die Argumente für None getestet.


  

Wie kann man es richtig machen? Eine Lösung ist Vermeiden Sie die Verwendung wandelbar Standardwerte für Argumente . Aber das ist kaum zufrieden stellend, wie von Zeit zu Zeit eine neue Liste ein nützlicher Standard ist. Es gibt einige komplexe Lösungen wie ein Dekorateur für Funktionen definieren, die tief kopiert alle Argumente. Dies ist ein viel des Guten, und das Problem kann leicht folgt gelöst werden, wie:

class ext(myobj):
    def __init__(self, resources=None):
        if not resources:
            resources = []
        self._resources = resources
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top