2009-12-23 5 views
7
from copy import* 
a=[1,2,3,4] 
c={'a':'aaa'} 
print c 
#{'a': 'aaa'} 
b=deepcopy(a,c) 
print b 

print c 
# print {'a': 'aaa', 10310992: 3, 10310980: 4, 10311016: 1, 11588784: [1, 2, 3, 4, [1, 2, 3, 4]], 11566456: [1, 2, 3, 4], 10311004: 2} 

warum c Druck, dassWelchen Zweck hat der zweite Parameter von docepy, Memo?

Bitte versuchen, den Code zu verwenden, anstatt Text, weil mein Englisch ist nicht sehr gut, danke

in django.utils.tree.py

def __deepcopy__(self, memodict): 
     """ 
     Utility method used by copy.deepcopy(). 
     """ 
     obj = Node(connector=self.connector, negated=self.negated) 
     obj.__class__ = self.__class__ 
     obj.children = deepcopy(self.children, memodict) 
     obj.subtree_parents = deepcopy(self.subtree_parents, memodict) 
     return obj 



import copy 
memo = {} 
x1 = range(5) 
x2=range(6,9) 
x3=[2,3,4,11] 
y1 = copy.deepcopy(x1, memo) 
y2=copy.deepcopy(x2, memo) 
y3=copy.deepcopy(x3,memo) 
print memo 
print id(y1),id(y2),id(y3) 
y1[0]='www' 
print y1,y2,y3 
print memo 

Druck:

{10310992: 3, 10310980: 4, 10311016: 1, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4]], 10311028: 0, 11566456: [0, 1, 2, 3, 4], 10311004: 2} 
{11572448: [6, 7, 8], 10310992: 3, 10310980: 4, 10311016: 1, 11572368: [2, 3, 4, 11], 10310956: 6, 10310896: 11, 10310944: 7, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4], 6, 7, 8, [6, 7, 8], 11, [2, 3, 4, 11]], 10311028: 0, 11566456: [0, 1, 2, 3, 4], 10310932: 8, 10311004: 2} 
11572408 11581280 11580960 
['www', 1, 2, 3, 4] [6, 7, 8] [2, 3, 4, 11] 
{11572448: [6, 7, 8], 10310992: 3, 10310980: 4, 10311016: 1, 11572368: [2, 3, 4, 11], 10310956: 6, 10310896: 11, 10310944: 7, 11588784: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4], 6, 7, 8, [6, 7, 8], 11, [2, 3, 4, 11]], 10311028: 0, 11566456: ['www', 1, 2, 3, 4], 10310932: 8, 10311004: 2} 

Antwort

7

Es ist das memo dict, wo ID-zu-Objekt-Korrespondenz beibehalten wird, um komplexe Objektgraphen perfekt zu rekonstruieren. Schwer zu "den Code verwenden", aber lassen Sie uns versuchen:

>>> import copy 
>>> memo = {} 
>>> x = range(5) 
>>> y = copy.deepcopy(x, memo) 
>>> memo 
{399680: [0, 1, 2, 3, 4], 16790896: 3, 16790884: 4, 16790920: 1, 
438608: [0, 1, 2, 3, 4, [0, 1, 2, 3, 4]], 16790932: 0, 16790908: 2} 
>>> 

und

>>> id(x) 
399680 
>>> for j in x: print j, id(j) 
... 
0 16790932 
1 16790920 
2 16790908 
3 16790896 
4 16790884 

so, wie Sie die IDs sind genau richtig sehen. Auch:

>>> for k, v in memo.items(): print k, id(v) 
... 
399680 435264 
16790896 16790896 
16790884 16790884 
16790920 16790920 
438608 435464 
16790932 16790932 
16790908 16790908 

Sie sehen die Identität für die (unveränderlichen) Ganzzahlen.

hier ist also ein Graph:

>>> z = [x, x] 
>>> t = copy.deepcopy(z, memo) 
>>> print id(t[0]), id(t[1]), id(y) 
435264 435264 435264 

, so dass Sie alle subcopies sehen, sind die gleichen Objekte wie y (da wir das Memo wiederverwendet).

+0

Wie kann ich 'memo' korrekt verwenden, wenn Sätze von Objekten mit Referenzen zueinander tief kopiert werden? http://StackOverflow.com/q/41395369/2745116 – CGFoX

+0

Randnotiz: direktes Kopieren von Ints und anderen unveränderlichen Primitiven ist ein [spezieller Fall von 'decopy'] (https://github.com/python/cpython/blob/ 3.6/Lib/copy.py # L195) um Speicherzuweisungen zu vermeiden. int-Literale außerhalb von 0-256 erstellen jedes Mal neue PyObjects. [Hier ist eine Demonstration] (https://gist.github.com/theY4Kman/da91d297cb27bb5e041702694b837fef). – theY4Kman

3

Sie können mehr lesen, indem Sie die Python onlin Überprüfung e Dokumentation:

http://docs.python.org/library/copy.html

Die deepcopy() Funktion ist rekursiv, und es wird seinen Weg nach unten durch ein tief verschachteltes Objekt zu arbeiten. Es verwendet ein Wörterbuch, um Objekte zu erkennen, die es zuvor gesehen hat, um eine Endlosschleife zu erkennen. Sie sollten dieses Wörterbuch einfach ignorieren.

class A(object): 
    def __init__(self, *args): 
     self.lst = args 

class B(object): 
    def __init__(self): 
     self.x = self 

def my_deepcopy(arg): 
    try: 
     obj = type(arg)() # get new, empty instance of type arg 
     for key in arg.__dict__: 
      obj.__dict__[key] = my_deepcopy(arg.__dict__[key]) 
     return obj 
    except AttributeError: 
     return type(arg)(arg) # return new instance of a simple type such as str 

a = A(1, 2, 3) 
b = B() 
b.x is b # evaluates to True 
c = my_deepcopy(a) # works fine 
c = my_deepcopy(b) # stack overflow, recurses forever 

from copy import deepcopy 
c = deepcopy(b) # this works because of the second, hidden, dict argument 

Ignorieren Sie einfach das zweite, versteckte, dict-Argument. Versuche nicht, es zu benutzen.

0

Hier ist eine kurze Darstellung ich zur Erklärung dieses mir verwendet:

a = [1,2,3] 
memo = {} 
b = copy.deepcopy(a,memo) 
# now memo = {139907464678864: [1, 2, 3], 9357408: 1, 9357440: 2, 9357472: 3, 28258000: [1, 2, 3, [1, 2, 3]]} 

key = 139907464678864 
print(id(a) == key)    #True 
print(id(b) == key)    #False 
print(id(a) == id(memo[key]))  #False 
print(id(b) == id(memo[key]))  #True 

mit anderen Worten:

memo[id_of_initial_object] = copy_of_initial_object 
0

Niemand oben gab ein gutes Beispiel dafür, wie es zu benutzen.

Hier ist, was ich tue:

def __deepcopy__(self, memo): 
    copy = type(self)() 
    memo[id(self)] = self 
    copy._member1 = self._member1 
    copy._member2 = deepcopy(self._member2, memo) 
    return copy 

Wo member1 ist ein Objekt nicht erforderlich deep (wie ein String oder Integer) und member2 ist eine, die tut, wie ein anderen benutzerdefinierten Typ oder eine Liste oder dict.

Ich habe den obigen Code auf stark verschlungenen Objektdiagrammen verwendet und es funktioniert sehr gut.

Wenn Sie wollen auch Ihre Klassen pickleable (für Datei Speichern/Laden) machen, gibt es nicht analog Memo param für getstate/setstate, mit anderen Worten die Beize System hält irgendwie den Überblick über bereits referenzierte Objekte , also brauchst du dir keine Sorgen zu machen.

Die oben genannten Arbeiten auf PyQt5 Klassen, die Sie von erben (sowie Beizen - zum Beispiel kann ich deep oder eine benutzerdefinierte QMainWindow Beize, QWidget, QGraphicsItem, etc.)

Wenn es einige Code-Initialisierung in Ihrem Konstruktor, der neue Objekte erstellt, z. B. ein CustomWidget (QWidget), das ein neues CustomScene (QGraphicsScene) erstellt, aber die Szene von einem CustomWidget in ein neues pikieren oder kopieren möchte, um einen new=True Parameter zu erstellen in Ihrem __init__ und sagen:

def __init__(..., new=True): 
    .... 
    if new: 
     self._scene = CustomScene() 

def __deepcopy__(self, memo): 
    copy = type(self)(..., new=False) 
    .... 
    copy._scene = deepcopy(self._scene, memo) 
    .... 

die sicherstellt, Sie erstellen kein CustomScene (oder eine große Klasse, die viel initialisiert) zweimal. Sie sollten auch die gleiche Einstellung (new=False) in Ihrer __setstate__ Methode verwenden, zB .:

def __setstate__(self, data): 
    self.__init__(...., new=False) 
    self._member1 = data['member 1'] 
    ..... 

es andere Wege geben um die oben zu bekommen, aber das ist das, was ich zu konvergiert und häufig verwenden.

Warum habe ich auch über Beizen gesprochen? Weil Sie beide in jeder Anwendung in der Regel möchten, und Sie sie gleichzeitig verwalten. Wenn Sie Ihrer Klasse ein Mitglied hinzufügen, fügen Sie es zu setstate, getstate, und decopy code hinzu. Ich würde es zu einer Regel machen, dass Sie für jede neue Klasse, die Sie erstellen, die obigen drei Methoden erstellen, wenn Sie das Kopieren/Einfügen einer Datei speichern/laden in Ihre App planen. Alternative ist JSON und speichern/laden Sie sich selbst, aber dann gibt es viel mehr Arbeit für Sie zu tun, einschließlich Memoisierung.

Also alles zu unterstützen, die oben, müssen Sie __deepcopy__, __setstate__, and __getstate__ Methoden und importieren deep:

from copy import deepcopy 

, und wenn Sie Ihre Beize loader/Schoner Funktionen schreiben (wo Sie pickle.load()/ pickle.dump() rufen Sie Ihre Objekthierarchie laden/speichern/graph) do import _pickle as pickle für die besten Geschwindigkeiten (_pickle ist etwas schneller C impl, die normalerweise mit Ihren App-Anforderungen kompatibel ist).

Verwandte Themen