2009-12-23 26 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} 

tại sao c in rằngMục đích của thông số thứ hai của bản in sâu, bản ghi nhớ là gì?

Hãy cố gắng sử dụng mã này, chứ không phải là văn bản, vì tiếng Anh của tôi không phải là rất tốt, cảm ơn bạn

trong 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 

in:

{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} 

Trả lời

7

Đó là số memo dict, trong đó đối tượng id-to-đối tượng được lưu giữ để tái tạo lại các biểu đồ đối tượng phức tạp một cách hoàn hảo. Khó "sử dụng mã", nhưng, chúng ta hãy thử:

>>> 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 

nên như bạn thấy các ID là hoàn toàn đúng. Đồng thời:

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

bạn sẽ thấy danh tính cho số nguyên (không thay đổi).

Vì vậy, đây là một biểu đồ:

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

vì vậy bạn thấy tất cả các subcopies là các đối tượng tương tự như y (vì chúng ta tái sử dụng các bản ghi nhớ).

+0

Làm cách nào để sử dụng 'memo' một cách chính xác khi tập hợp các đối tượng có tham chiếu sâu với nhau? http://stackoverflow.com/q/41395369/2745116 – CGFoX

+0

Lưu ý phụ: sao chép trực tiếp các int và các nguyên thủy bất biến khác là [trường hợp đặc biệt của 'deepcopy'] (https://github.com/python/cpython/blob/ 3.6/Lib/copy.py # L195) để tránh phân bổ bộ nhớ. int literals bên ngoài 0-256 sẽ tạo ra các PyObject mới mỗi lần. [Đây là một cuộc biểu tình] (https://gist.github.com/theY4Kman/da91d297cb27bb5e041702694b837fef). – theY4Kman

3

Bạn có thể đọc thêm bằng cách kiểm tra onlin Python tài liệu điện tử:

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

Chức năng deepcopy() là đệ quy, và nó sẽ làm việc theo cách của mình xuống thông qua một đối tượng lồng nhau sâu sắc. Nó sử dụng một từ điển để phát hiện các đối tượng mà nó đã thấy trước đó, để phát hiện một vòng lặp vô hạn. Bạn chỉ nên bỏ qua từ điển này.

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 

Chỉ cần bỏ qua đối số thứ hai, ẩn, dict. Đừng cố gắng sử dụng nó.

0

Dưới đây là một minh hoạ nhanh chóng tôi sử dụng để giải thích điều này với chính mình:

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 

nói cách khác:

memo[id_of_initial_object] = copy_of_initial_object 
0

Không ai ở trên đã đưa ra một ví dụ tốt về làm thế nào để sử dụng nó.

Dưới đây là những gì tôi làm:

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

đâu member1 là một đối tượng không đòi hỏi deepcopy (giống như một chuỗi hoặc số nguyên), và member2 là một trong đó không, giống như một loại tùy chỉnh hoặc một danh sách hoặc dict.

Tôi đã sử dụng mã ở trên trên biểu đồ đối tượng có độ rối cao và nó hoạt động rất tốt.

Nếu bạn cũng muốn làm cho lớp học của bạn pickleable (đối với tập tin lưu/tải), không có tương tự như bản ghi nhớ param cho getstate/setstate, nói cách khác hệ thống dưa bằng cách nào đó theo dõi các đối tượng đã tham chiếu , vì vậy bạn không cần phải lo lắng.

Các công trình trên trên lớp PyQt5 mà bạn được thừa hưởng từ (cũng như tẩy - ví dụ tôi có thể deepcopy hoặc dưa một QMainWindow tùy chỉnh, QWidget, QGraphicsItem, vv)

Nếu có một số mã khởi tạo trong của bạn constructor tạo các đối tượng mới, ví dụ một CustomWidget (QWidget) tạo ra một CustomScene mới (QGraphicsScene), nhưng bạn muốn chọn hoặc sao chép cảnh từ một CustomWidget sang một CustomWidget mới, một cách là tạo một tham số new=True trong số __init__ và nói:

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

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

Điều đó đảm bảo bạn không tạo ra một CustomScene (hoặc một số lớp lớn mà có rất nhiều khởi tạo) hai lần! Bạn cũng nên sử dụng các thiết lập tương tự (new=False) trong phương pháp __setstate__ của bạn, Eg .:

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

Có nhiều cách khác để có được xung quanh trên, nhưng đây là một trong tôi hội tụ đến và sử dụng thường xuyên.

Tại sao tôi cũng nói về việc tẩy? Bởi vì bạn sẽ muốn cả hai trong bất kỳ ứng dụng nào thường và bạn duy trì chúng cùng một lúc. Nếu bạn thêm thành viên vào lớp học của mình, bạn thêm thành viên đó vào mã ngôn ngữ setstate, getstate, . Tôi sẽ làm cho nó một quy tắc cho bất kỳ lớp học mới bạn thực hiện, bạn tạo ra ba phương pháp trên nếu bạn có kế hoạch làm sao chép/dán một tập tin lưu/tải trong ứng dụng của bạn. Thay thế là JSON và lưu/tải bản thân, nhưng sau đó có rất nhiều công việc để bạn làm bao gồm cả việc ghi nhớ.

Vì vậy, để hỗ trợ tất cả các bên trên, bạn cần __deepcopy__, __setstate__, and __getstate__ phương pháp và nhập khẩu deepcopy:

from copy import deepcopy 

, và khi bạn viết dưa loader/chức năng tiết kiệm của bạn (nơi bạn gọi pickle.load()/ pickle.dump() để nạp/lưu hệ thống phân cấp đối tượng của bạn/graph) làm import _pickle as pickle cho tốc độ tốt nhất (_pickle là một số C nhanh hơn mà thường tương thích với các yêu cầu ứng dụng của bạn).

Các vấn đề liên quan