Cách sao chép từ điển và chỉ chỉnh sửa bản sao


855

Có ai đó giải thích điều này cho tôi biết không? Điều này không có ý nghĩa gì với tôi.

Tôi sao chép một từ điển vào một cái khác và chỉnh sửa cái thứ hai và cả hai đều được thay đổi. Tại sao chuyện này đang xảy ra?

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict1
>>> dict2
{'key2': 'value2', 'key1': 'value1'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key2': 'WHY?!', 'key1': 'value1'}

4
PythonTutor là tuyệt vời để hiển thị các tài liệu tham khảo Python. Đây là mã này ở bước cuối cùng . Bạn có thể nhìn thấy dict1dict2chỉ vào cùng một dict.
wjandrea

Câu trả lời:


883

Python không bao giờ sao chép các đối tượng. Khi bạn đặt dict2 = dict1, bạn đang làm cho chúng tham chiếu đến cùng một đối tượng chính xác, vì vậy khi bạn thay đổi nó, tất cả các tham chiếu đến nó tiếp tục tham chiếu đến đối tượng ở trạng thái hiện tại.

Nếu bạn muốn sao chép dict (rất hiếm), bạn phải làm như vậy rõ ràng với

dict2 = dict(dict1)

hoặc là

dict2 = dict1.copy()

26
Có thể tốt hơn để nói "dict2 và dict1 trỏ đến cùng một từ điển", bạn không thay đổi dict1 hoặc dict2 mà là những gì họ trỏ đến.
GrayWizardx 17/03/2016

276
Cũng lưu ý rằng dict.copy () là nông, nếu có một danh sách lồng nhau / vv trong đó các thay đổi sẽ được áp dụng cho cả hai. IIRC. Deepcopy sẽ tránh điều đó.
Sẽ

16
Nó không hoàn toàn chính xác rằng python không bao giờ sao chép các đối tượng. Các kiểu dữ liệu nguyên thủy, chẳng hạn như int, float và bool, cũng được coi là các đối tượng (chỉ cần thực hiện dir(1)để thấy điều đó), nhưng chúng được sao chép ngầm.
daniel kullmann

17
@danielkullmann, tôi nghĩ bạn có thể hiểu sai về Python dựa trên cách các ngôn ngữ khác bạn đã xử lý công việc. Trong Python, a) Không có khái niệm về "kiểu dữ liệu nguyên thủy". int, floatvà các boolthể hiện là các đối tượng Python thực và b) các đối tượng của các loại này không được sao chép hoàn toàn khi bạn vượt qua chúng, không phải ở cấp độ ngữ nghĩa Python chắc chắn và thậm chí không phải là một chi tiết triển khai trong CPython.
Mike Graham

39
Những lời hoa mỹ không có căn cứ như "Bản sao sâu được coi là có hại" là không có ích. Tất cả những thứ khác đều bằng nhau, sao chép nông một cấu trúc dữ liệu phức tạp nhiều khả năng mang lại các vấn đề trường hợp cạnh không mong muốn hơn là sao chép sâu cùng cấu trúc. Một bản sao trong đó sửa đổi sửa đổi đối tượng ban đầu không phải là bản sao; đó là một lỗi Ergo, hầu hết các trường hợp sử dụng hoàn toàn nên gọi copy.deepcopy()chứ không phải dict()hoặc dict.copy(). Câu trả lời ngắn gọn của Imran nằm ở phía bên phải của sự tỉnh táo, không giống như câu trả lời này.
Cecil Curry

647

Khi bạn chỉ định dict2 = dict1, bạn không tạo một bản sao dict1, nó dict2sẽ chỉ là một tên khác cho dict1.

Để sao chép các loại có thể thay đổi như từ điển, sử dụng copy/ deepcopycủa copymô-đun.

import copy

dict2 = copy.deepcopy(dict1)

80
Đối với bất kỳ từ điển nào tôi từng làm việc, deepcopy là thứ tôi cần ... Tôi chỉ mất vài giờ do một lỗi là do tôi không nhận được một bản sao hoàn chỉnh của một từ điển lồng nhau và những thay đổi của tôi đối với các mục lồng nhau đã ảnh hưởng đến bản gốc .
flutefreak7

7
Tương tự ở đây. deepcopy () không lừa. Đã làm rối tung các ký tự lồng nhau của tôi trong bộ đệm xoay bằng cách thêm dấu thời gian vào 'bản sao' của sự kiện ban đầu. Cảm ơn bạn!
fxstein

8
Điều này thực sự nên được đánh dấu là câu trả lời chính xác; Câu trả lời này là chung chung và nó cũng hoạt động cho một từ điển từ điển.
orezvani

30
Đây phải là câu trả lời được chấp nhận. Biện pháp tu từ "Bản sao sâu được coi là có hại" không có căn cứ được nhúng trong phần bình luận của câu trả lời được chấp nhận hiện tại mời gọi những tai ương đồng bộ hóa khi sao chép từ điển lồng nhau (như những tài liệu ở đây) và nên được thách thức như vậy.
Cecil Curry

deepcopy là cách để đi trong trường hợp cấu trúc từ điển phức tạp. dict1.copy () chỉ đơn giản là sao chép các giá trị của khóa dưới dạng tham chiếu và không phải là đối tượng.
Rohith N

182

Trong khi dict.copy()dict(dict1)tạo ra một bản sao, chúng chỉ là bản sao nông . Nếu bạn muốn một bản sao sâu , copy.deepcopy(dict1)được yêu cầu. Một ví dụ:

>>> source = {'a': 1, 'b': {'m': 4, 'n': 5, 'o': 6}, 'c': 3}
>>> copy1 = x.copy()
>>> copy2 = dict(x)
>>> import copy
>>> copy3 = copy.deepcopy(x)
>>> source['a'] = 10  # a change to first-level properties won't affect copies
>>> source
{'a': 10, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> copy3
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}
>>> source['b']['m'] = 40  # a change to deep properties WILL affect shallow copies 'b.m' property
>>> source
{'a': 10, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy1
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy2
{'a': 1, 'c': 3, 'b': {'m': 40, 'o': 6, 'n': 5}}
>>> copy3  # Deep copy's 'b.m' property is unaffected
{'a': 1, 'c': 3, 'b': {'m': 4, 'o': 6, 'n': 5}}

Về các bản sao nông và sâu, từ các tài liệu mô-đun Pythoncopy :

Sự khác biệt giữa sao chép nông và sâu chỉ có liên quan đến các đối tượng ghép (các đối tượng có chứa các đối tượng khác, như danh sách hoặc thể hiện lớp):

  • Một bản sao nông xây dựng một đối tượng ghép mới và sau đó (trong phạm vi có thể) chèn các tham chiếu vào nó cho các đối tượng được tìm thấy trong bản gốc.
  • Một bản sao sâu xây dựng một đối tượng ghép mới và sau đó, đệ quy, chèn các bản sao vào đối tượng được tìm thấy trong bản gốc.

2
đây phải là câu trả lời đúng vì nó không lặp lại rõ ràng trên dict và có thể được sử dụng cho các cấu trúc chính khác.
Nikkolasg

27
Chỉ cần làm rõ: w=copy.deepcopy(x)là dòng chính.
rượu vào

Sự khác biệt giữa dict2 = dict1và là dict2 = copy.deepcopy(dict1)gì?
TheTank

1
@TheTank, y = x làm cho hai tên (tham chiếu) tham chiếu đến cùng một đối tượng, tức là "y là x" là True. Mọi thay đổi được thực hiện trên đối tượng thông qua x đều tương đương với một thay đổi tương tự thông qua y. Tuy nhiên, u, v, w là các tham chiếu đến các đối tượng mới khác nhau có các giá trị được sao chép từ x trong khi khởi tạo. Đối với sự khác biệt giữa u, v (nông copy) và w (deepcopy), xin vui lòng kiểm tra docs.python.org/2/library/copy.html
gpanda

63

Trên python 3.5+, có một cách dễ dàng hơn để đạt được một bản sao nông bằng cách sử dụng toán tử giải nén **. Được xác định bởi Pep 448 .

>>>dict1 = {"key1": "value1", "key2": "value2"}
>>>dict2 = {**dict1}
>>>print(dict2)
{'key1': 'value1', 'key2': 'value2'}
>>>dict2["key2"] = "WHY?!"
>>>print(dict1)
{'key1': 'value1', 'key2': 'value2'}
>>>print(dict2)
{'key1': 'value1', 'key2': 'WHY?!'}

** giải nén từ điển thành một từ điển mới sau đó được gán cho dict2.

Chúng tôi cũng có thể xác nhận rằng mỗi từ điển có một id riêng biệt.

>>>id(dict1)
 178192816

>>>id(dict2)
 178192600

Nếu cần một bản sao sâu thì copy.deepcopy () vẫn là cách để sử dụng.


3
Điều này trông cực kỳ giống như con trỏ trong C ++. Rất vui khi hoàn thành nhiệm vụ, nhưng dễ đọc, tôi có xu hướng không thích loại toán tử này.
Ernesto

1
Nó có một kiểu nhìn giống nhau ... nhưng khi hợp nhất nhiều từ điển lại với nhau, cú pháp trông khá mượt mà.
YAMTorre

2
Hãy cẩn thận với điều đó, nó chỉ thực hiện một bản sao nông.
Sebastian Dressler

bạn đúng @SebastianDressler, tôi sẽ điều chỉnh makde. thnx.
YAMTorre

2
Sử dụng đầy đủ nếu bạn muốn tạo bản sao với một số chi tiết:dict2 = {**dict1, 'key3':'value3'}
evg656e

48

Cách tốt nhất và dễ nhất để tạo một bản sao của một dict trong cả Python 2.7 và 3 là ...

Để tạo một bản sao của từ điển đơn giản (cấp độ đơn):

1. Sử dụng phương thức dict () , thay vì tạo tham chiếu trỏ đến dict hiện có.

my_dict1 = dict()
my_dict1["message"] = "Hello Python"
print(my_dict1)  # {'message':'Hello Python'}

my_dict2 = dict(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

2. Sử dụng phương thức update () tích hợp của từ điển python.

my_dict2 = dict()
my_dict2.update(my_dict1)
print(my_dict2)  # {'message':'Hello Python'}

# Made changes in my_dict1 
my_dict1["name"] = "Emrit"
print(my_dict1)  # {'message':'Hello Python', 'name' : 'Emrit'}
print(my_dict2)  # {'message':'Hello Python'}

Để tạo một bản sao của từ điển lồng nhau hoặc phức tạp:

Sử dụng mô-đun sao chép tích hợp , cung cấp một hoạt động sao chép chung và sâu. Mô-đun này có mặt trong cả Python 2.7 và 3. *

import copy

my_dict2 = copy.deepcopy(my_dict1)

6
Tôi tin rằng dict()tạo ra một bản sao nông không phải là một bản sao sâu. Có nghĩa là nếu bạn có một lồng nhau dictthì bên ngoài dictsẽ là một bản sao nhưng chính tả bên trong sẽ là một tham chiếu đến chính tả bên trong ban đầu.
shmuels

@shmuels vâng, cả hai phương pháp này sẽ tạo ra một bản sao nông chứ không phải bản sâu. Xem, câu trả lời cập nhật.
AKay Nirala

37

Bạn cũng có thể tạo một từ điển mới với sự hiểu từ điển. Điều này tránh nhập bản sao.

dout = dict((k,v) for k,v in mydict.items())

Tất nhiên trong python> = 2.7 bạn có thể làm:

dout = {k:v for k,v in mydict.items()}

Nhưng đối với compat ngược., Phương pháp hàng đầu là tốt hơn.


4
Điều này đặc biệt hữu ích nếu bạn muốn kiểm soát nhiều hơn về cách thức và chính xác những gì được sao chép. +1
Tiếp

14
Lưu ý rằng phương pháp này không thực hiện một bản sao sâu và nếu bạn muốn một bản sao nông mà không cần kiểm soát các khóa được sao chép, d2 = dict.copy(d1)thì cũng không yêu cầu nhập bất kỳ.
Jarek Piórkowski 23/8/2015

1
@ JarekPiórkowski: hoặc bạn có thể gọi một phương thức như một phương thức:d2 = d1.copy()
Azat Ibrakov

Lưu ý rằng bạn không cần sự hiểu biết trong ví dụ đầu tiên. dict.itemsđã trả về một cặp khóa / giá trị lặp lại. Vì vậy, bạn chỉ có thể sử dụng dict(mydict.items())(bạn cũng có thể chỉ sử dụng dict(mydict)). Nó có thể hữu ích để có sự hiểu biết nếu bạn muốn lọc các mục.
Paul Rooney

22

Ngoài các giải pháp được cung cấp khác, bạn có thể sử dụng **để tích hợp từ điển vào một từ điển trống, ví dụ:

shallow_copy_of_other_dict = {**other_dict}.

Bây giờ bạn sẽ có một bản sao "nông" other_dict.

Áp dụng cho ví dụ của bạn:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = {**dict1}
>>> dict2
{'key1': 'value1', 'key2': 'value2'}
>>> dict2["key2"] = "WHY?!"
>>> dict1
{'key1': 'value1', 'key2': 'value2'}
>>>

Con trỏ: Sự khác biệt giữa các bản sao nông và sâu


1
Điều này dẫn đến một bản sao nông, không phải là một bản sao sâu.
sytech

1
Tôi đã thử điều này nhưng gặp khó khăn. Điều này chỉ hoạt động cho python 3.5 trở lên. python.org/dev/peps/pep-0448
ThatGuyRob

19

Các câu lệnh gán trong Python không sao chép các đối tượng, chúng tạo ra các ràng buộc giữa một mục tiêu và một đối tượng.

vì vậy, dict2 = dict1nó dẫn đến một ràng buộc khác giữa dict2và đối tượngdict1 đề cập đến.

nếu bạn muốn sao chép một dict, bạn có thể sử dụng copy module. Mô-đun sao chép có hai giao diện:

copy.copy(x)
Return a shallow copy of x.

copy.deepcopy(x)
Return a deep copy of x.

Sự khác biệt giữa sao chép nông và sâu chỉ có liên quan đến các đối tượng ghép (các đối tượng có chứa các đối tượng khác, như danh sách hoặc thể hiện lớp):

Một bản sao nông xây dựng một đối tượng ghép mới và sau đó (trong phạm vi có thể) chèn các tham chiếu vào nó cho các đối tượng được tìm thấy trong bản gốc.

Một bản sao sâu xây dựng một đối tượng ghép mới và sau đó, đệ quy, chèn các bản sao vào đối tượng được tìm thấy trong bản gốc.

Ví dụ: trong python 2.7.9:

>>> import copy
>>> a = [1,2,3,4,['a', 'b']]
>>> b = a
>>> c = copy.copy(a)
>>> d = copy.deepcopy(a)
>>> a.append(5)
>>> a[4].append('c')

và kết quả là:

>>> a
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> b
[1, 2, 3, 4, ['a', 'b', 'c'], 5]
>>> c
[1, 2, 3, 4, ['a', 'b', 'c']]
>>> d
[1, 2, 3, 4, ['a', 'b']]

10

Bạn có thể sao chép và chỉnh sửa bản sao mới được xây dựng trong một lần bằng cách gọi dict tạo với các đối số từ khóa bổ sung:

>>> dict1 = {"key1": "value1", "key2": "value2"}
>>> dict2 = dict(dict1, key2="WHY?!")
>>> dict1
{'key2': 'value2', 'key1': 'value1'}
>>> dict2
{'key2': 'WHY?!', 'key1': 'value1'}

9

Điều này làm tôi bối rối, ban đầu, bởi vì tôi đến từ nền C.

Trong C, một biến là một vị trí trong bộ nhớ với một kiểu xác định. Gán cho một biến sao chép dữ liệu vào vị trí bộ nhớ của biến.

Nhưng trong Python, các biến hoạt động giống như con trỏ tới các đối tượng. Vì vậy, việc gán một biến cho một biến khác không tạo ra một bản sao, nó chỉ làm cho tên biến đó trỏ đến cùng một đối tượng.


5
Các biến python hoạt động giống như các tham chiếu c ++
Ruggero Turra

7
Bởi vì mọi thứ trong Python là một đối tượng! diveintopython.net/getting_to_ledge_python/ ' (vâng, phản hồi này đã trễ nhiều năm, nhưng có lẽ nó có ích với ai đó!)
grimman

1
Tôi tin rằng ngữ nghĩa của ngôn ngữ Python nói rằng không có "biến". Chúng được gọi là "tài liệu tham khảo có tên"; có nghĩa là tham chiếu đến một đối tượng là một chuỗi cú pháp trong mã. Một đối tượng có thể có nhiều tài liệu tham khảo được đặt tên cho nó. Các đối tượng bất biến như ints và float và str dụ chỉ có một thể hiện của nó cho mỗi tiến trình. Số nguyên trong 1 trong bộ nhớ không thay đổi thành 2 hoặc một số giá trị khác tại cùng một địa chỉ bộ nhớ khi bạn thực hiện điều này myvalue = 1 myvalue = 2
DevPlayer

7

Mỗi biến trong python (những thứ như thế dict1hay strhay__builtins__ là một con trỏ đến một số ẩn "đối tượng" thuần khiết bên trong máy.

Nếu bạn đặt dict1 = dict2, bạn chỉ cần trỏ dict1đến cùng một đối tượng (hoặc vị trí bộ nhớ hoặc bất kỳ tương tự nào bạn muốn) như dict2. Bây giờ, đối tượng được tham chiếu bởi dict1cùng một đối tượng được tham chiếu bởi dict2.

Bạn có thể kiểm tra: dict1 is dict2nên được True. Ngoài ra, id(dict1)nên giống nhưid(dict2) .

Bạn muốn dict1 = copy(dict2), hoặcdict1 = deepcopy(dict2) .

Sự khác biệt giữa copydeepcopy? deepcopysẽ đảm bảo rằng các yếu tố củadict2 (bạn đã chỉ ra nó trong một danh sách?) cũng là bản sao.

Tôi không sử dụng deepcopynhiều - thường là cách thực hành kém để viết mã cần nó (theo ý kiến ​​của tôi).


Tôi chỉ nhận ra rằng tôi cần phải luôn luôn sử dụng deepcopy để khi tôi sao chép một từ điển lồng nhau và bắt đầu sửa đổi các mục lồng nhau, các hiệu ứng chỉ xảy ra trên bản sao chứ không phải bản gốc.
flutefreak7

6

dict1là một biểu tượng tham chiếu đến một đối tượng từ điển cơ bản. Chỉ định dict1để dict2chỉ gán cùng một tham chiếu. Thay đổi giá trị của khóa thông qua dict2biểu tượng sẽ thay đổi đối tượng bên dưới, điều này cũng ảnh hưởng đếndict1 . Điều này thật khó hiểu.

Lý do về các giá trị bất biến dễ dàng hơn nhiều so với các tài liệu tham khảo, vì vậy hãy tạo các bản sao bất cứ khi nào có thể:

person = {'name': 'Mary', 'age': 25}
one_year_later = {**person, 'age': 26}  # does not mutate person dict

Đây là cú pháp giống như:

one_year_later = dict(person, age=26)

5

dict2 = dict1không sao chép từ điển. Nó chỉ đơn giản cung cấp cho bạn lập trình viên một cách thứ hai ( dict2) để tham khảo cùng một từ điển.


5
>>> dict2 = dict1
# dict2 is bind to the same Dict object which binds to dict1, so if you modify dict2, you will modify the dict1

Có nhiều cách để sao chép đối tượng Dict, tôi chỉ đơn giản là sử dụng

dict_1 = {
           'a':1,
           'b':2
         }
dict_2 = {}
dict_2.update(dict_1)

12
dict_2 = dict_1.copy()là hiệu quả và hợp lý hơn nhiều.
Jean-François Fabre

2
Lưu ý rằng nếu bạn có một dict bên trong dict1, với dict_1.copy (), những thay đổi bạn thực hiện trên dict bên trong dict_2 cũng được áp dụng cho dict bên trong trong dict_1. Trong trường hợp này, bạn nên sử dụng copy.deepcopy (dict_1) thay thế.
xếp hàng

1

Như những người khác đã giải thích, tích hợp dictkhông làm những gì bạn muốn. Nhưng trong Python2 (và có lẽ 3 cũng vậy), bạn có thể dễ dàng tạo một ValueDictlớp sao chép =để bạn có thể chắc chắn rằng bản gốc sẽ không thay đổi.

class ValueDict(dict):

    def __ilshift__(self, args):
        result = ValueDict(self)
        if isinstance(args, dict):
            dict.update(result, args)
        else:
            dict.__setitem__(result, *args)
        return result # Pythonic LVALUE modification

    def __irshift__(self, args):
        result = ValueDict(self)
        dict.__delitem__(result, args)
        return result # Pythonic LVALUE modification

    def __setitem__(self, k, v):
        raise AttributeError, \
            "Use \"value_dict<<='%s', ...\" instead of \"d[%s] = ...\"" % (k,k)

    def __delitem__(self, k):
        raise AttributeError, \
            "Use \"value_dict>>='%s'\" instead of \"del d[%s]" % (k,k)

    def update(self, d2):
        raise AttributeError, \
            "Use \"value_dict<<=dict2\" instead of \"value_dict.update(dict2)\""


# test
d = ValueDict()

d <<='apples', 5
d <<='pears', 8
print "d =", d

e = d
e <<='bananas', 1
print "e =", e
print "d =", d

d >>='pears'
print "d =", d
d <<={'blueberries': 2, 'watermelons': 315}
print "d =", d
print "e =", e
print "e['bananas'] =", e['bananas']


# result
d = {'apples': 5, 'pears': 8}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
d = {'apples': 5, 'pears': 8}
d = {'apples': 5}
d = {'watermelons': 315, 'blueberries': 2, 'apples': 5}
e = {'apples': 5, 'pears': 8, 'bananas': 1}
e['bananas'] = 1

# e[0]=3
# would give:
# AttributeError: Use "value_dict<<='0', ..." instead of "d[0] = ..."

Vui lòng tham khảo mẫu sửa đổi lvalue được thảo luận ở đây: Python 2.7 - cú pháp sạch để sửa đổi giá trị . Quan sát chính là strinthành xử như các giá trị trong Python (mặc dù chúng thực sự là các đối tượng bất biến dưới mui xe). Trong khi bạn đang quan sát điều đó, xin vui lòng cũng quan sát rằng không có gì đặc biệt kỳ diệu về strhoặc int. dictcó thể được sử dụng theo nhiều cách giống nhau, và tôi có thể nghĩ về nhiều trường hợp có ValueDictý nghĩa.


0

đoạn mã sau, nằm trên dicts theo cú pháp json nhanh hơn 3 lần so với deepcopy

def CopyDict(dSrc):
    try:
        return json.loads(json.dumps(dSrc))
    except Exception as e:
        Logger.warning("Can't copy dict the preferred way:"+str(dSrc))
        return deepcopy(dSrc)

0

tôi gặp phải một hành vi đặc biệt khi cố gắng sao chép sâu thuộc tính từ điển của lớp với việc gán nó cho biến

new = copy.deepcopy(my_class.a)không hoạt động tức là sửa newđổi sửa đổimy_class.a

nhưng nếu bạn làm old = my_class.avà sau đó new = copy.deepcopy(old)nó hoạt động hoàn hảo tức là sửa đổi newkhông ảnh hưởng đếnmy_class.a

Tôi không chắc tại sao điều này xảy ra, nhưng hy vọng nó sẽ giúp tiết kiệm một vài giờ! :)


Vì vậy, làm thế nào để bạn thực hiện một deepcopy my_class.a?
Anthony

Không phải là cách tốt nhất. Phản ứng tốt là dưới đây.
David Beauchemin

-1

bởi vì, dict2 = dict1, dict2 giữ tham chiếu đến dict1. Cả dict1 và dict2 đều chỉ đến cùng một vị trí trong bộ nhớ. Đây chỉ là một trường hợp bình thường trong khi làm việc với các đối tượng có thể thay đổi trong python. Khi bạn đang làm việc với các đối tượng có thể thay đổi trong python, bạn phải cẩn thận vì khó gỡ lỗi. Chẳng hạn như ví dụ sau đây.

 my_users = {
        'ids':[1,2],
        'blocked_ids':[5,6,7]
 }
 ids = my_users.get('ids')
 ids.extend(my_users.get('blocked_ids')) #all_ids
 print ids#output:[1, 2, 5, 6, 7]
 print my_users #output:{'blocked_ids': [5, 6, 7], 'ids': [1, 2, 5, 6, 7]}

Mục đích ví dụ này là để có được tất cả các id người dùng bao gồm các id bị chặn. Rằng chúng tôi đã nhận được từ biến id nhưng chúng tôi cũng vô tình cập nhật giá trị của my_users . khi bạn mở rộng id với block_ids my_users đã được cập nhật vì id tham chiếu đến my_users .


-1

Sao chép bằng cách sử dụng vòng lặp for:

orig = {"X2": 674.5, "X3": 245.0}

copy = {}
for key in orig:
    copy[key] = orig[key]

print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 674.5, 'X3': 245.0}
copy["X2"] = 808
print(orig) # {'X2': 674.5, 'X3': 245.0}
print(copy) # {'X2': 808, 'X3': 245.0}

1
Điều này chỉ hoạt động cho từ điển đơn giản. Tại sao không sử dụng deepcopy, được xây dựng rõ ràng cho mục đích này?
Anthony

Không phải là cách tốt nhất. Phản ứng tốt là dưới đây.
David Beauchemin

-6

Bạn có thể sử dụng trực tiếp:

dict2 = eval(repr(dict1))

trong đó đối tượng dict2 là một bản sao độc lập của dict1, vì vậy bạn có thể sửa đổi dict2 mà không ảnh hưởng đến dict1.

Điều này làm việc cho bất kỳ loại đối tượng.


4
Câu trả lời này không chính xác, và không nên được sử dụng. Ví dụ, một lớp do người dùng định nghĩa có thể không có một lớp thích hợp __repr__để được xây dựng lại bằng eval, cũng như lớp của đối tượng có thể được gọi trong phạm vi hiện tại. Ngay cả khi gắn với các loại tích hợp, điều này sẽ thất bại nếu cùng một đối tượng được lưu trữ dưới nhiều khóa, khi dict2đó sẽ có hai đối tượng riêng biệt. Một từ điển tự tham khảo, nơi dict1chứa chính nó, thay vào đó sẽ chứa Ellipsis. Nó sẽ tốt hơn để sử dụngdict1.copy()
Eldritch Cheese

Các đối tượng (hoặc "giá trị") không được mong đợi sẽ luôn có một đại diện trung thành theo chuỗi ký tự, không phải theo cách thông thường có thể đọc được của con người trong mọi trường hợp.
Alexey
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.