Ich möchte eine Kopie eines Objekts erstellen. Ich möchte, dass das neue Objekt alle Eigenschaften des alten Objekts (Werte der Felder) besitzt. Aber ich möchte unabhängige Objekte haben. Wenn ich also die Werte der Felder des neuen Objekts ändere, sollte das alte Objekt davon nicht betroffen sein.
198
Du meinst dann ein veränderliches Objekt.
In Python 3 erhalten Listen eine
copy
Methode (in 2 würden Sie ein Slice verwenden, um eine Kopie zu erstellen):Flache Kopien
Flache Kopien sind nur Kopien des äußersten Behälters.
list.copy
ist eine flache Kopie:Sie erhalten keine Kopie der Innenobjekte. Sie sind dasselbe Objekt. Wenn sie also mutiert sind, wird die Änderung in beiden Containern angezeigt.
Tiefe Kopien
Tiefe Kopien sind rekursive Kopien jedes inneren Objekts.
Änderungen werden nicht im Original, sondern nur in der Kopie berücksichtigt.
Unveränderliche Gegenstände
Unveränderliche Objekte müssen normalerweise nicht kopiert werden. Wenn Sie es versuchen, gibt Python Ihnen nur das ursprüngliche Objekt:
Tupel haben nicht einmal eine Kopiermethode, also versuchen wir es mit einem Slice:
Aber wir sehen, es ist das gleiche Objekt:
Ähnliches gilt für Strings:
und für Frozensets, obwohl sie eine
copy
Methode haben:Wann unveränderliche Objekte kopiert werden sollen
Unveränderliche Objekte sollten kopiert werden, wenn ein veränderbares inneres Objekt kopiert werden muss.
Wie wir sehen können, ändert sich das Original nicht , wenn das innere Objekt der Kopie mutiert ist .
Benutzerdefinierte Objekte
Benutzerdefinierte Objekte speichern Daten normalerweise in einem
__dict__
Attribut oder in__slots__
(einer tupelartigen Speicherstruktur).Um ein kopierbares Objekt zu erstellen, definieren Sie
__copy__
(für flache Kopien) und / oder__deepcopy__
(für tiefe Kopien).Beachten Sie, dass
deepcopy
ein Memo-Wörterbuch vonid(original)
(oder Identitätsnummern) Kopien enthält. Um ein gutes Verhalten bei rekursiven Datenstrukturen zu erzielen, stellen Sie sicher, dass Sie noch keine Kopie erstellt haben, und geben Sie diese gegebenenfalls zurück.Machen wir also ein Objekt:
Und
copy
macht eine flache Kopie:Und
deepcopy
jetzt macht eine tiefe Kopie:quelle
Flache Kopie mit
copy.copy()
Tiefes Kopieren mit
copy.deepcopy()
Dokumentation: https://docs.python.org/3/library/copy.html
Getestet auf Python 3.6.5.
quelle
Ich glaube, dass das Folgende mit vielen gut erzogenen, in Python klassifizierten Klassen funktionieren sollte:
(Natürlich spreche ich hier nicht von "tiefen Kopien", was eine andere Geschichte ist und was möglicherweise kein sehr klares Konzept ist - wie tief ist tief genug?)
Gemäß meinen Tests mit Python 3 wird für unveränderliche Objekte wie Tupel oder Zeichenfolgen dasselbe Objekt zurückgegeben (da keine flache Kopie eines unveränderlichen Objekts erstellt werden muss), für Listen oder Wörterbücher wird jedoch eine unabhängige flache Kopie erstellt .
Natürlich funktioniert diese Methode nur für Klassen, deren Konstruktoren sich entsprechend verhalten. Mögliche Anwendungsfälle: Erstellen einer flachen Kopie einer Standard-Python-Containerklasse.
quelle
__init__
Methode respektieren . Daher dachte ich, dass diese Methode für bestimmte Zwecke gut genug sein könnte. In jedem Fall bin ich an informativen Kommentaren zu diesem Vorschlag interessiert.class Foo(object): def __init__(self, arg): super(Foo, self).__init__() self.arg = arg
Basic so wie es nur geht. Wenn ich das tue Dasfoo = Foo(3) bar = copy(foo) print(foo.arg) # 3 print(bar.arg) # <__main__.Foo object at ...>
bedeutet, dass Ihrecopy
Funktion selbst für die grundlegendsten Klassen unterbrochen ist. Auch hier ist es ein ordentlicher Trick (daher kein DV), aber keine Antwort.copy.copy
Methode zum Erstellen flacher Kopien gibt, aber vielleicht naiv scheint es mir, dass es in der Verantwortung der Klasse liegen sollte, einen "Konstruktor für flache Kopien" bereitzustellen. In einem solchen Fall, warum nicht die gleiche Schnittstelle zur Verfügung stellen wiedict
undlist
? Wenn Ihre Klasse die Verantwortung für das Kopieren ihrer Objekte übernehmen möchte, warum nicht eineif isinstance(arg, type(self))
Klausel hinzufügen__init__
?