Hướng dẫn what is a shallow copy in python? - một bản sao nông trong python là gì?

Mã nguồn: lib/copy.py Lib/copy.py


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ục tiêu và đối tượng. Đối với các bộ sưu tập có thể thay đổi hoặc chứa các mục có thể thay đổi, đôi khi một bản sao là cần thiết để người ta có thể thay đổi một bản sao mà không thay đổi cái kia. Mô -đun này cung cấp các hoạt động sao chép nông và sâu chung (giải thích bên dưới).

Tóm tắt giao diện:

sao chép.Copy (x) ¶copy(x)

Trả lại một bản sao nông của x.

sao chép.deepcopy (x [, memo]) ¶deepcopy(x[, memo])

Trả lại một bản sao sâu của x.

ExceptionCopy.error¶ copy.Error

Được nâng lên cho các lỗi cụ thể của mô -đun.

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 hỗn hợp (các đối tượng có chứa các đối tượng khác, như danh sách hoặc trường hợp lớp):

  • Một bản sao nông xây dựng một đối tượng hợp chất mới và sau đó (trong phạm vi có thể) chèn các tham chiếu vào nó vào 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 hợp chất mới và sau đó, đệ quy, chèn các bản sao vào nó của các đối tượng được tìm thấy trong bản gốc.

Hai vấn đề thường tồn tại với các hoạt động sao chép sâu mà don lồng tồn tại với các hoạt động sao chép nông:

  • Các đối tượng đệ quy (các đối tượng hợp chất, trực tiếp hoặc gián tiếp, chứa một tham chiếu đến chính chúng) có thể gây ra một vòng lặp đệ quy.

  • Bởi vì bản sao sâu sao chép mọi thứ mà nó có thể sao chép quá nhiều, chẳng hạn như dữ liệu dự định được chia sẻ giữa các bản sao.

Hàm

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
7 tránh những vấn đề này bằng cách:

  • Giữ một từ điển

    >>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    >>> ys = list(xs)  # Make a shallow copy
    
    8 của các đối tượng đã được sao chép trong quá trình sao chép hiện tại; và

  • Cho phép các lớp do người dùng xác định ghi đè hoạt động sao chép hoặc tập hợp các thành phần được sao chép.

Mô -đun này không sao chép các loại như mô -đun, phương thức, dấu vết ngăn xếp, khung ngăn xếp, tệp, ổ cắm, cửa sổ hoặc bất kỳ loại tương tự nào. Nó không sao chép các chức năng và các lớp (nông và sâu), bằng cách trả về đối tượng ban đầu không thay đổi; Điều này tương thích với cách chúng được xử lý bằng mô -đun

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
9.

Các bản sao nông của từ điển có thể được thực hiện bằng cách sử dụng

>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
0 và các danh sách bằng cách gán một lát của toàn bộ danh sách, ví dụ,
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
1.

Các lớp có thể sử dụng các giao diện tương tự để kiểm soát sao chép mà họ sử dụng để kiểm soát Pickling. Xem mô tả của mô -đun

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
9 để biết thông tin về các phương pháp này. Trên thực tế, mô -đun
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 sử dụng các hàm Pickle đã đăng ký từ mô -đun
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
4.

Để một lớp xác định triển khai bản sao của riêng mình, nó có thể xác định các phương thức đặc biệt

>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
5 và
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
6. Cái trước được gọi để thực hiện hoạt động sao chép nông; Không có lập luận bổ sung được thông qua. Cái sau được gọi để thực hiện hoạt động sao chép sâu; Nó được thông qua một đối số, từ điển
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
8. Nếu việc triển khai
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
6 cần tạo một bản sao sâu của một thành phần, nó sẽ gọi hàm
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
7 với thành phần là đối số đầu tiên và từ điển ghi nhớ là đối số thứ hai. Từ điển ghi nhớ nên được coi là một đối tượng mờ đục.

Xem thêm

Mô -đun
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
9

Thảo luận về các phương pháp đặc biệt được sử dụng để hỗ trợ truy xuất và phục hồi trạng thái đối tượng.

Các câu lệnh gán trong Python không tạo các bản sao của các đối tượng, chúng chỉ liên kết tên với một đối tượng. Đối với các đối tượng bất biến, điều đó thường không tạo ra sự khác biệt.

Nhưng để làm việc với các đối tượng có thể thay đổi hoặc bộ sưu tập các đối tượng có thể thay đổi, bạn có thể đang tìm kiếm một cách để tạo ra các bản sao thực sự của các bản sao hoặc các bản sao của các đối tượng này.

Về cơ bản, đôi khi bạn muốn các bản sao mà bạn có thể sửa đổi mà không tự động sửa đổi bản gốc cùng một lúc. Trong bài viết này, tôi sẽ cung cấp cho bạn danh sách về cách sao chép hoặc sao chép các đối tượng của bản sao trong Python 3 và một số cảnh báo liên quan.

Lưu ý: Hướng dẫn này được viết với Python 3 trong tâm trí nhưng có rất ít sự khác biệt giữa Python 2 và 3 khi nói đến việc sao chép các đối tượng. Khi có sự khác biệt, tôi sẽ chỉ ra chúng trong văn bản. This tutorial was written with Python 3 in mind but there is little difference between Python 2 and 3 when it comes to copying objects. When there are differences I will point them out in the text.

Hãy bắt đầu bằng cách xem xét cách sao chép các bộ sưu tập tích hợp Python. Có thể sao chép các bộ sưu tập đột biến tích hợp của Python, như Danh sách, Dicts và Bộ có thể được sao chép bằng cách gọi các chức năng nhà máy của chúng trên một bộ sưu tập hiện có:

new_list = list(original_list)
new_dict = dict(original_dict)
new_set = set(original_set)

Tuy nhiên, phương pháp này đã giành được công việc cho các đối tượng tùy chỉnh và, trên hết, nó chỉ tạo ra các bản sao nông. Đối với các đối tượng hỗn hợp như danh sách, dicts và bộ, có một sự khác biệt quan trọng giữa sao chép nông và sâu:

  • Một bản sao nông có nghĩa là xây dựng một đối tượng bộ sưu tập mới và sau đó điền nó với các tham chiếu đến các đối tượng con được tìm thấy trong bản gốc. Về bản chất, một bản sao nông chỉ là một cấp độ sâu. Quá trình sao chép không tái phát và do đó won đã tạo ra các bản sao của các đối tượng con.shallow copy means constructing a new collection object and then populating it with references to the child objects found in the original. In essence, a shallow copy is only one level deep. The copying process does not recurse and therefore won’t create copies of the child objects themselves.

  • Một bản sao sâu làm cho quá trình sao chép đệ quy. Nó có nghĩa là đầu tiên xây dựng một đối tượng bộ sưu tập mới và sau đó chiếm giữ nó một cách đệ quy với các bản sao của các đối tượng con được tìm thấy trong bản gốc. Sao chép một đối tượng theo cách này đi bộ toàn bộ cây đối tượng để tạo ra một bản sao hoàn toàn độc lập của đối tượng ban đầu và tất cả trẻ em của nó.deep copy makes the copying process recursive. It means first constructing a new collection object and then recursively populating it with copies of the child objects found in the original. Copying an object this way walks the whole object tree to create a fully independent clone of the original object and all of its children.

Tôi biết, đó là một chút của một miệng. Vì vậy, hãy để Lôi nhìn vào một số ví dụ để lái xe về sự khác biệt này giữa các bản sao sâu và nông.

Tạo các bản sao nông

Trong ví dụ dưới đây, chúng tôi sẽ tạo một danh sách lồng nhau mới và sau đó sao chép nó một cách nông cạn với chức năng nhà máy

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
1:

>>>

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy

Điều này có nghĩa là

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2 bây giờ sẽ là một đối tượng mới và độc lập có cùng nội dung với
>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3. Bạn có thể xác minh điều này bằng cách kiểm tra cả hai đối tượng:

>>>

>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Điều này có nghĩa là

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2 bây giờ sẽ là một đối tượng mới và độc lập có cùng nội dung với
>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3. Bạn có thể xác minh điều này bằng cách kiểm tra cả hai đối tượng:

>>>

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Điều này có nghĩa là

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2 bây giờ sẽ là một đối tượng mới và độc lập có cùng nội dung với
>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3. Bạn có thể xác minh điều này bằng cách kiểm tra cả hai đối tượng:

Để xác nhận

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2 thực sự độc lập với bản gốc, hãy để đưa ra một thử nghiệm nhỏ. Bạn có thể thử và thêm một trình phụ mới vào bản gốc (
>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3) và sau đó kiểm tra để đảm bảo sửa đổi này đã không ảnh hưởng đến bản sao (
>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2):

Như bạn có thể thấy, điều này có hiệu ứng mong đợi. Việc sửa đổi danh sách được sao chép ở cấp độ hời hợt của người Viking không có vấn đề gì cả.

Tuy nhiên, vì chúng tôi chỉ tạo một bản sao nông của danh sách gốc,

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2 vẫn chứa các tham chiếu đến các đối tượng con gốc được lưu trữ trong
>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3.

>>>

>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]

Điều này có nghĩa là

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2 bây giờ sẽ là một đối tượng mới và độc lập có cùng nội dung với
>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3. Bạn có thể xác minh điều này bằng cách kiểm tra cả hai đối tượng:

Để xác nhận

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2 thực sự độc lập với bản gốc, hãy để đưa ra một thử nghiệm nhỏ. Bạn có thể thử và thêm một trình phụ mới vào bản gốc (
>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3) và sau đó kiểm tra để đảm bảo sửa đổi này đã không ảnh hưởng đến bản sao (
>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
2):

Như bạn có thể thấy, điều này có hiệu ứng mong đợi. Việc sửa đổi danh sách được sao chép ở cấp độ hời hợt của người Viking không có vấn đề gì cả.

  • Tuy nhiên, vì chúng tôi chỉ tạo một bản sao nông của danh sách gốc,
    >>> xs.append(['new sublist'])
    >>> xs
    [[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
    >>> ys
    [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    
    2 vẫn chứa các tham chiếu đến các đối tượng con gốc được lưu trữ trong
    >>> xs.append(['new sublist'])
    >>> xs
    [[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
    >>> ys
    [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    
    3.
  • Làm thế nào bạn có thể tạo các bản sao (nông và sâu) của các đối tượng tùy ý, bao gồm các lớp tùy chỉnh?

Câu trả lời cho những câu hỏi này nằm ở mô -đun

>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
5 trong thư viện tiêu chuẩn Python. Mô -đun này cung cấp một giao diện đơn giản để tạo các bản sao nông và sâu của các đối tượng Python tùy ý.

Tạo các bản sao sâu

Hãy để lặp lại ví dụ sao chép danh sách trước đó, nhưng với một sự khác biệt quan trọng. Lần này, chúng tôi sẽ tạo một bản sao sâu bằng hàm

>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
6 được xác định trong mô -đun
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
5 thay thế: thay vào đó:

>>>

>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)

Khi bạn kiểm tra

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 và bản sao của nó
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9 mà chúng tôi đã tạo bằng
>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
0, bạn sẽ thấy rằng cả hai đều trông giống hệt nhau một lần nữa giống như trong ví dụ trước:

>>>

>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Khi bạn kiểm tra

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 và bản sao của nó
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9 mà chúng tôi đã tạo bằng
>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
0, bạn sẽ thấy rằng cả hai đều trông giống hệt nhau một lần nữa giống như trong ví dụ trước:

Tuy nhiên, nếu bạn thực hiện sửa đổi cho một trong các đối tượng con trong đối tượng gốc (

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3), bạn sẽ thấy rằng sửa đổi này đã giành được ảnh hưởng đến bản sao sâu (
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9).

>>>

>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
>>> zs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]

Khi bạn kiểm tra

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 và bản sao của nó
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9 mà chúng tôi đã tạo bằng
>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
0, bạn sẽ thấy rằng cả hai đều trông giống hệt nhau một lần nữa giống như trong ví dụ trước:

Tuy nhiên, nếu bạn thực hiện sửa đổi cho một trong các đối tượng con trong đối tượng gốc (

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3), bạn sẽ thấy rằng sửa đổi này đã giành được ảnh hưởng đến bản sao sâu (
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9).

Cả hai đối tượng, bản gốc và bản sao, lần này hoàn toàn độc lập.

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 đã được nhân bản đệ quy, bao gồm tất cả các đối tượng con của nó:

Bạn có thể muốn dành một chút thời gian để ngồi xuống với thông dịch viên Python và chơi qua các ví dụ này ngay bây giờ. Bao bọc đầu của bạn xung quanh việc sao chép các đối tượng dễ dàng hơn khi bạn trải nghiệm và chơi với các ví dụ.

Nhân tiện, bạn cũng có thể tạo các bản sao nông bằng cách sử dụng hàm trong mô -đun

>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
5. Hàm
>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
5 tạo ra các bản sao nông của các đối tượng.

Điều này rất hữu ích nếu bạn cần giao tiếp rõ ràng rằng bạn đang tạo một bản sao nông ở đâu đó trong mã của bạn. Sử dụng

>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
5 cho phép bạn chỉ ra thực tế này. Tuy nhiên, đối với các bộ sưu tập tích hợp, nó đã xem xét nhiều pythonic hơn để sử dụng danh sách, dict và thiết lập các chức năng nhà máy để tạo các bản sao nông.

Sao chép các đối tượng Python tùy ý

class Point:
    def __init__(self, x, y):
        self.x = x
        self.y = y

    def __repr__(self):
        return f'Point({self.x!r}, {self.y!r})'

Câu hỏi chúng ta vẫn cần trả lời là làm thế nào để chúng ta tạo các bản sao (nông và sâu) của các đối tượng tùy ý, bao gồm các lớp tùy chỉnh. Hãy cùng xem xét điều đó ngay bây giờ.

Một lần nữa, mô -đun

>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
5 đến giải cứu của chúng tôi. Các hàm
>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
5 và
>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
0 của nó có thể được sử dụng để nhân đôi bất kỳ đối tượng nào.
The above example uses a Python 3.6 f-string to construct the string returned by
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
1. On Python 2 and versions of Python 3 before 3.6 you’d use a different string formatting expression, for example:

def __repr__(self):
    return 'Point(%r, %r)' % (self.x, self.y)

Một lần nữa, cách tốt nhất để hiểu cách sử dụng chúng là với một thử nghiệm đơn giản. Tôi sẽ dựa trên điều này trên ví dụ sao chép danh sách trước đó. Hãy bắt đầu bằng cách xác định một lớp điểm 2D đơn giản:

>>>

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
0

Khi bạn kiểm tra

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 và bản sao của nó
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9 mà chúng tôi đã tạo bằng
>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
0, bạn sẽ thấy rằng cả hai đều trông giống hệt nhau một lần nữa giống như trong ví dụ trước:

>>>

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
1

Khi bạn kiểm tra

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 và bản sao của nó
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9 mà chúng tôi đã tạo bằng
>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
0, bạn sẽ thấy rằng cả hai đều trông giống hệt nhau một lần nữa giống như trong ví dụ trước:

Tuy nhiên, nếu bạn thực hiện sửa đổi cho một trong các đối tượng con trong đối tượng gốc (

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3), bạn sẽ thấy rằng sửa đổi này đã giành được ảnh hưởng đến bản sao sâu (
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9).

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
2

Cả hai đối tượng, bản gốc và bản sao, lần này hoàn toàn độc lập.

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 đã được nhân bản đệ quy, bao gồm tất cả các đối tượng con của nó:

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
3

Bạn có thể muốn dành một chút thời gian để ngồi xuống với thông dịch viên Python và chơi qua các ví dụ này ngay bây giờ. Bao bọc đầu của bạn xung quanh việc sao chép các đối tượng dễ dàng hơn khi bạn trải nghiệm và chơi với các ví dụ.

>>>

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
4

Khi bạn kiểm tra

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 và bản sao của nó
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9 mà chúng tôi đã tạo bằng
>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
0, bạn sẽ thấy rằng cả hai đều trông giống hệt nhau một lần nữa giống như trong ví dụ trước:

>>>

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
5

Khi bạn kiểm tra

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 và bản sao của nó
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9 mà chúng tôi đã tạo bằng
>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
0, bạn sẽ thấy rằng cả hai đều trông giống hệt nhau một lần nữa giống như trong ví dụ trước:

>>>

>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> ys = list(xs)  # Make a shallow copy
6

Khi bạn kiểm tra

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 và bản sao của nó
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9 mà chúng tôi đã tạo bằng
>>> import copy
>>> xs = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
>>> zs = copy.deepcopy(xs)
0, bạn sẽ thấy rằng cả hai đều trông giống hệt nhau một lần nữa giống như trong ví dụ trước:

Tuy nhiên, nếu bạn thực hiện sửa đổi cho một trong các đối tượng con trong đối tượng gốc (

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3), bạn sẽ thấy rằng sửa đổi này đã giành được ảnh hưởng đến bản sao sâu (
>>> xs[1][0] = 'X'
>>> xs
[[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
9).

Cả hai đối tượng, bản gốc và bản sao, lần này hoàn toàn độc lập.

>>> xs.append(['new sublist'])
>>> xs
[[1, 2, 3], [4, 5, 6], [7, 8, 9], ['new sublist']]
>>> ys
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
3 đã được nhân bản đệ quy, bao gồm tất cả các đối tượng con của nó:

3 điều cần nhớ

  • Tạo một bản sao nông của một đối tượng đã giành được các đối tượng con bản sao. Do đó, bản sao không hoàn toàn độc lập với bản gốc.
  • Một bản sao sâu của một đối tượng sẽ đệ quy các đối tượng con. Bản sao hoàn toàn độc lập với bản gốc, nhưng việc tạo một bản sao sâu là chậm hơn.
  • Bạn có thể sao chép các đối tượng tùy ý (bao gồm các lớp tùy chỉnh) với mô -đun
    >>> xs[1][0] = 'X'
    >>> xs
    [[1, 2, 3], ['X', 5, 6], [7, 8, 9], ['new sublist']]
    >>> ys
    [[1, 2, 3], ['X', 5, 6], [7, 8, 9]]
    
    5.

Nếu bạn muốn đào sâu hơn vào các kỹ thuật lập trình Python cấp trung cấp khác, hãy xem phần thưởng miễn phí này:

Bản sao nông trong Python là gì?

Một bản sao nông có nghĩa là xây dựng một đối tượng bộ sưu tập mới và sau đó điền nó với các tham chiếu đến các đối tượng con được tìm thấy trong bản gốc. Về bản chất, một bản sao nông chỉ là một cấp độ sâu. Quá trình sao chép không tái phát và do đó sẽ không tạo bản sao của chính các đối tượng con.constructing a new collection object and then populating it with references to the child objects found in the original. In essence, a shallow copy is only one level deep. The copying process does not recurse and therefore won't create copies of the child objects themselves.

Bản sao sâu và nông trong Python là gì?

Một bản sao nông xây dựng một đối tượng hợp chất mới và sau đó (trong phạm vi có thể) chèn các tham chiếu vào nó vào 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 hợp chất mới và sau đó, đệ quy, chèn các bản sao vào nó của các đối tượng được tìm thấy trong bản gốc.

Có nghĩa là gì bởi bản sao nông?

Một bản sao nông của một đối tượng là một bản sao có thuộc tính có cùng các tài liệu tham khảo (trỏ đến cùng các giá trị cơ bản) như của đối tượng nguồn mà bản sao được tạo.a copy whose properties share the same references (point to the same underlying values) as those of the source object from which the copy was made.

Sự khác biệt giữa bản sao nông và bản sao sâu là gì?

Trong bản sao nông, một bản sao của đối tượng gốc được lưu trữ và chỉ có địa chỉ tham chiếu cuối cùng được sao chép. Bản sao sâu, bản sao của đối tượng gốc và các bản sao lặp đi lặp lại được lưu trữ. In Deep copy, the copy of the original object and the repetitive copies both are stored.