Какова цель второго параметра, memo?
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}
зачем c печатать, что
Попробуйте использовать код, а не текст, потому что мой английский не очень хорош, спасибо
в 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
print:
{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}
Ответы
Ответ 1
Это memo
dict, где поддерживается соответствие id-to-object, чтобы полностью восстановить сложные графы объектов. Трудно "использовать код", но попробуйте:
>>> 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}
>>>
и
>>> id(x)
399680
>>> for j in x: print j, id(j)
...
0 16790932
1 16790920
2 16790908
3 16790896
4 16790884
так как вы видите, что идентификаторы в точности совпадают. Также:
>>> for k, v in memo.items(): print k, id(v)
...
399680 435264
16790896 16790896
16790884 16790884
16790920 16790920
438608 435464
16790932 16790932
16790908 16790908
вы видите идентификатор для (неизменяемых) целых чисел.
Итак, вот график:
>>> z = [x, x]
>>> t = copy.deepcopy(z, memo)
>>> print id(t[0]), id(t[1]), id(y)
435264 435264 435264
поэтому вы видите, что все подкопии - это те же объекты, что и y (поскольку мы повторно использовали заметку).
Ответ 2
Вы можете прочитать больше, проверив онлайн-документацию Python:
http://docs.python.org/library/copy.html
Функция deepcopy()
рекурсивна, и она будет пробиваться через глубоко вложенный объект. Он использует словарь для обнаружения объектов, которые он видел раньше, для обнаружения бесконечного цикла. Вы должны просто игнорировать этот словарь.
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
Просто игнорируйте второй, скрытый аргумент dict. Не пытайтесь использовать его.
Ответ 3
Никто выше не дал хорошего примера того, как его использовать.
Вот что я делаю:
def __deepcopy__(self, memo):
copy = type(self)()
memo[id(self)] = copy
copy._member1 = self._member1
copy._member2 = deepcopy(self._member2, memo)
return copy
Где member1
- это объект, для которого не требуется глубокая копия (например, строка или целое число), а member2
- тот, который требует, например, другой пользовательский тип, список или dict.
Я использовал приведенный выше код для сильно запутанных графов объектов, и он работает очень хорошо.
Если вы также хотите, чтобы ваши классы были доступными для выбора (для сохранения/загрузки файла), то нет аналогичного параметра памятки для getstate/setstate, другими словами, система pickle каким-то образом отслеживает уже упоминаемые объекты, поэтому вам не нужно беспокоиться,
Вышеприведенное работает для классов PyQt5, от которых вы наследуете (а также для выбора - например, я могу сделать глубокую копию или выбрать собственный QMainWindow, QWidget, QGraphicsItem и т.д.)
Если в вашем конструкторе есть некоторый код инициализации, который создает новые объекты, например CustomWidget (QWidget), который создает новый CustomScene (QGraphicsScene), но вы хотите выбрать или скопировать сцену из одного CustomWidget в новый, то один из способов - сделать new=True
параметр new=True
в вашем __init__
и сказать:
def __init__(..., new=True):
....
if new:
self._scene = CustomScene()
def __deepcopy__(self, memo):
copy = type(self)(..., new=False)
....
copy._scene = deepcopy(self._scene, memo)
....
Это гарантирует, что вы не создадите CustomScene (или какой-то большой класс, который много инициализирует) дважды! Вам также следует использовать ту же настройку (new=False
) в вашем методе __setstate__
, например:
def __setstate__(self, data):
self.__init__(...., new=False)
self._member1 = data['member 1']
.....
Есть и другие способы обойти вышеупомянутое, но это тот, к которому я часто прибегал и использую.
Почему я тоже говорил о мариновании? Потому что вы, как правило, захотите оба в любом приложении, и вы будете поддерживать их одновременно. Если вы добавляете члена в свой класс, вы добавляете его в код setstate, getstate и deepcopy. Я бы сделал правило, что для любого нового класса вы создаете три вышеупомянутых метода, если планируете копировать/вставлять файл, сохранять/загружать файл в своем приложении. Альтернативой является JSON и сохранение/загрузка самостоятельно, но тогда вам предстоит еще много работы, включая запоминание.
Таким образом, для поддержки всего вышеперечисленного вам понадобятся __deepcopy__, __setstate__, and __getstate__
и для импорта deepcopy:
from copy import deepcopy
и когда вы пишете свои функции загрузчика /pickle.load()/pickle.dump()
заставки (где вы вызываете pickle.load()/pickle.dump()
для загрузки/сохранения вашей иерархии объектов/графика), import _pickle as pickle
для достижения наилучших скоростей (_pickle
немного быстрее) C Impl, который обычно совместим с требованиями вашего приложения).
Ответ 4
Вот краткая иллюстрация, которую я использовал для объяснения этого себе:
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
Другими словами:
memo[id_of_initial_object] = copy_of_initial_object