Deepcopy() trong Python là gì?
Trong chương này, chúng tôi sẽ đề cập đến câu hỏi làm thế nào để sao chép danh sách và danh sách lồng nhau. Các vấn đề mà chúng ta sẽ gặp phải là các vấn đề chung của các kiểu dữ liệu có thể thay đổi. Cố gắng sao chép danh sách có thể là một trải nghiệm khó khăn đối với người mới. Nhưng trước đó, chúng tôi muốn tóm tắt một số hiểu biết từ chương trước "Kiểu dữ liệu và biến". Python thậm chí còn thể hiện một hành vi lạ đối với người mới bắt đầu sử dụng ngôn ngữ này - so với một số ngôn ngữ lập trình truyền thống khác - khi gán và sao chép các loại dữ liệu đơn giản như số nguyên và chuỗi. Sự khác biệt giữa sao chép nông và sâu chỉ liên quan đến các đối tượng phức hợp, tôi. e. các đối tượng chứa các đối tượng khác, như danh sách hoặc thể hiện của lớp Show Trong đoạn mã sau, y trỏ đến cùng một vị trí bộ nhớ với X. Chúng ta có thể thấy điều này bằng cách áp dụng hàm id() trên x và y. Tuy nhiên, không giống như các con trỏ "thực" như trong C và C++, mọi thứ sẽ thay đổi khi chúng ta gán một giá trị mới cho y. Trong trường hợp này, y sẽ nhận một vị trí bộ nhớ riêng, như chúng ta đã thấy trong chương "Kiểu dữ liệu và biến" và có thể thấy trong ví dụ sau x = 3 y = x print(id(x), id(y)) ĐẦU RA94400598764928 94400598764928 y = 4 print(id(x), id(y)) ĐẦU RA94400598764928 94400598764960 print(x,y) ĐẦU RA3 4 Nhưng ngay cả khi hành vi bên trong này có vẻ lạ so với các ngôn ngữ lập trình như C, C++, Perl hay Java, kết quả có thể quan sát được của các nhiệm vụ trước đó là những gì chúng tôi đã dự đoán. e. nếu bạn không nhìn vào các giá trị id. Tuy nhiên, có thể có vấn đề nếu chúng ta sao chép các đối tượng có thể thay đổi như danh sách và từ điển Python chỉ tạo các bản sao thực, nếu phải, tôi. e. nếu người dùng, lập trình viên, yêu cầu nó một cách rõ ràng Chúng tôi sẽ giới thiệu cho bạn những vấn đề quan trọng nhất, có thể xảy ra khi sao chép các đối tượng có thể thay đổi như danh sách và từ điển Đào tạo Python trực tiếp Thưởng thức trang này? Nhìn thấy. Tổng quan về các khóa học Python trực tiếp đăng ký tại đây Các biến chia sẻ một đối tượngBạn đang ở trang này để tìm hiểu về cách sao chép các đối tượng, đặc biệt là các danh sách. Tuy nhiên, bạn cần rèn luyện tính kiên nhẫn. Chúng tôi muốn hiển thị thứ gì đó trông giống như một bản sao cho nhiều người mới bắt đầu nhưng không liên quan gì đến các bản sao colours1 = ["red", "blue"] colours2 = colours1 print(colours1, colours2) ĐẦU RA['red', 'blue'] ['red', 'blue'] Cả hai biến tham chiếu cùng một đối tượng danh sách. Nếu chúng ta nhìn vào danh tính của các biến print(x,y)0 và print(x,y)1, chúng ta có thể thấy rằng cả hai đều là tham chiếu đến cùng một đối tượng 94400598764928 944005987649280 ĐẦU RA94400598764928 944005987649281 Trong ví dụ trên, một danh sách đơn giản được gán cho colors1. Danh sách này được gọi là "danh sách nông", bởi vì nó không có cấu trúc lồng nhau, tôi. e. không có danh sách con nào được chứa trong danh sách. Trong bước tiếp theo, chúng tôi gán màu1 cho màu2 Hàm id() cho chúng ta thấy rằng cả hai biến đều trỏ đến cùng một đối tượng danh sách, i. e. họ chia sẻ đối tượng này Chúng tôi có hai tên biến print(x,y)0 và print(x,y)1, mà chúng tôi đã mô tả dưới dạng hình bầu dục màu vàng. Hộp màu xanh tượng trưng cho đối tượng danh sách. Một đối tượng danh sách bao gồm các tham chiếu đến các đối tượng khác. Trong ví dụ của chúng tôi, đối tượng danh sách, được tham chiếu bởi cả hai biến, tham chiếu đến hai đối tượng chuỗi, i. e. "đỏ và xanh". Bây giờ chúng ta phải kiểm tra, điều gì sẽ xảy ra, nếu chúng ta chỉ thay đổi một phần tử của danh sách print(x,y)1 hoặc print(x,y)0 Bây giờ chúng ta muốn xem điều gì sẽ xảy ra nếu chúng ta gán một đối tượng mới cho print(x,y)1. Như mong đợi, các giá trị của print(x,y)0 không thay đổi. Giống như trong ví dụ của chúng tôi trong chương "Kiểu dữ liệu và biến", một vị trí bộ nhớ mới đã được phân bổ cho print(x,y)1, vì chúng tôi đã chỉ định một danh sách hoàn toàn mới, tôi. e. một đối tượng danh sách mới cho biến này 94400598764928 944005987649280 ĐẦU RA94400598764928 944005987649281 94400598764928 944005987649282 ĐẦU RA94400598764928 944005987649283 94400598764928 944005987649284 ĐẦU RA94400598764928 944005987649283 94400598764928 944005987649286 ĐẦU RA94400598764928 944005987649287 Chúng tôi đã gán một đối tượng mới cho biến 'colors2'. Trong đoạn mã sau, chúng tôi sẽ thay đổi đối tượng danh sách bên trong bằng cách gán một giá trị mới cho phần tử thứ hai của danh sách 94400598764928 944005987649288 Hãy xem, những gì đã xảy ra chi tiết trong đoạn mã trước. Chúng tôi đã gán một giá trị mới cho phần tử thứ hai của colors2, i. e. phần tử có chỉ số 1. Nhiều người mới bắt đầu sẽ ngạc nhiên vì danh sách màu1 cũng được "tự động" thay đổi. Tất nhiên, chúng tôi không có hai danh sách. Chúng tôi chỉ có hai tên cho cùng một danh sách Giải thích là chúng ta đã không gán một đối tượng mới cho biến print(x,y)1. Chúng tôi đã thay đổi đối tượng được tham chiếu bởi print(x,y)1 trong nội bộ hoặc vì nó thường được gọi là "tại chỗ". Cả hai biến print(x,y)0 và print(x,y)1 vẫn trỏ đến cùng một đối tượng danh sách Sao chép danh sáchCuối cùng chúng ta đã đến chủ đề sao chép danh sách. Lớp 3 43 cung cấp phương thức 3 44 cho mục đích này. Mặc dù tên có vẻ rõ ràng, con đường này cũng có một điểm thu hút Có thể thấy được lợi ích nếu chúng ta sử dụng trợ giúp trên 3 44 94400598764928 944005987649289 ĐẦU RAy = 4 print(id(x), id(y))0 Nhiều người mới bắt đầu bỏ qua từ "nông cạn" ở đây. 3 46 cho chúng ta biết rằng một danh sách mới sẽ được tạo bằng phương thức 3 44. Danh sách mới này sẽ là bản sao 'nông' của danh sách gốc Về nguyên tắc, từ "nông" là không cần thiết hoặc thậm chí gây hiểu nhầm trong định nghĩa này Trước tiên, bạn nên nhớ danh sách trong Python là gì. Một danh sách trong Python là một đối tượng bao gồm một chuỗi tham chiếu đến các đối tượng Python. Sau đây là danh sách các chuỗi Danh sách mà biến 3 48 đang tham chiếu là danh sách các chuỗi. Về cơ bản, đối tượng danh sách chỉ là hộp màu xanh với các mũi tên, tôi. e. các tham chiếu đến các chuỗi. Bản thân các chuỗi không phải là một phần của danh sách y = 4 print(id(x), id(y))1 Ví dụ trước danh sách tên 3 48 là đồng nhất, tôi. e. nó chỉ bao gồm các chuỗi, vì vậy tất cả các phần tử có cùng kiểu dữ liệu. Nhưng bạn nên lưu ý rằng các tham chiếu của một danh sách có thể tham chiếu đến bất kỳ đối tượng nào. Danh sách sau đây colours1 = ["red", "blue"] colours2 = colours1 print(colours1, colours2)0 là một danh sách tổng quát hơn y = 4 print(id(x), id(y))2 Khi một danh sách được sao chép, chúng tôi sao chép các tài liệu tham khảo. Trong ví dụ của chúng tôi, đây là những hộp màu xanh được tham chiếu bởi 3 48 và bởi colours1 = ["red", "blue"] colours2 = colours1 print(colours1, colours2)0. Ý nghĩa của điều này được thể hiện trong chương phụ sau đây Đào tạo Python trực tiếp Thưởng thức trang này? Nhìn thấy. Tổng quan về các khóa học Python trực tiếp Các khóa học trực tuyến sắp tới Khái niệm cơ bản về Python cho người mới bắt đầu Khóa học nâng cao chuyên sâu Python dành cho kỹ sư và nhà khoa học Lập trình hướng đối tượng với Python đăng ký tại đây Các vấn đề về sao chép danh sáchSao chép danh sách có thể dễ dàng bị hiểu lầm và sự hiểu lầm này có thể dẫn đến những lỗi khó chịu. Chúng tôi sẽ trình bày điều này dưới dạng một câu chuyện tình yêu hơi khác Hãy tưởng tượng một người sống ở thành phố Constance. Thành phố nằm ở miền Nam nước Đức bên bờ hồ Constance (Bodensee trong tiếng Đức). Sông Rhine, bắt nguồn từ dãy núi Alps của Thụy Sĩ, chảy qua Hồ Constance và rời khỏi nó, lớn hơn đáng kể. Người này tên là Swen sống ở "Seestrasse", một trong những con phố đắt đỏ nhất của Constance. Căn hộ của anh có hướng nhìn thẳng ra hồ và thành phố Constance. Chúng tôi đặt một số thông tin về Swen trong cấu trúc danh sách sau đây y = 4 print(id(x), id(y))3 Một ngày đẹp trời, Sarah xinh đẹp gặp Swen, Hoàng tử quyến rũ của cô. Để cắt ngắn câu chuyện. Yêu từ cái nhìn đầu tiên và cô ấy chuyển đến sống với Swen Bây giờ, việc tạo tập dữ liệu cho Sarah là tùy thuộc vào chúng tôi. Chúng tôi lười biếng và chúng tôi sẽ tái chế dữ liệu của Swen, vì cô ấy sẽ sống với anh ấy trong cùng một căn hộ Chúng tôi sẽ sao chép dữ liệu của Swen và đổi tên thành Sarah y = 4 print(id(x), id(y))4 ĐẦU RAy = 4 print(id(x), id(y))5 Họ sống rất hòa thuận và yêu thương sâu sắc trong một thời gian dài, chẳng hạn như cả một ngày cuối tuần. Cô chợt nhận ra rằng Swen là một con quái vật. Anh ấy nhuộm bơ bằng mứt cam và mật ong và thậm chí tệ hơn, anh ấy trải đôi tất đã mòn của mình trong phòng ngủ. Cô ấy không mất nhiều thời gian để đưa ra quyết định quan trọng. Cô sẽ rời xa anh và căn hộ mơ ước Cô chuyển đến một con phố tên là Bücklestrasse. Một khu dân cư không nơi nào tốt đẹp bằng, nhưng ít nhất cô ấy đã tránh xa con quái vật Làm thế nào chúng ta có thể sắp xếp bước đi này từ quan điểm của Python? Đường phố có thể được truy cập bằng colours1 = ["red", "blue"] colours2 = colours1 print(colours1, colours2)3. Vì vậy, chúng tôi đặt vị trí này ở vị trí mới y = 4 print(id(x), id(y))6 Chúng ta có thể thấy rằng Sarah đã di chuyển thành công đến vị trí mới y = 4 print(id(x), id(y))7 ĐẦU RAy = 4 print(id(x), id(y))8 Đây có phải là kết thúc của câu chuyện của chúng tôi? y = 4 print(id(x), id(y))9 ĐẦU RA94400598764928 944005987649600 Swen là bám. Cô không thể thoát khỏi anh ta. Điều này có thể khá ngạc nhiên đối với một số. Tại sao nó như thế này? . Một đối tượng chuỗi ("Swen") và đối tượng kia vào danh sách lồng nhau (địa chỉ colours1 = ["red", "blue"] colours2 = colours1 print(colours1, colours2)5. Khi chúng tôi sử dụng 3 44, chúng tôi chỉ sao chép những tài liệu tham khảo này. Điều này có nghĩa là cả colours1 = ["red", "blue"] colours2 = colours1 print(colours1, colours2)7 và colours1 = ["red", "blue"] colours2 = colours1 print(colours1, colours2)8 đều tham chiếu đến cùng một đối tượng danh sách. Khi chúng tôi thay đổi danh sách lồng nhau này, nó sẽ hiển thị trong cả hai danh sách bản sao sâu từ bản sao Mô-đunMột giải pháp cho vấn đề được mô tả được cung cấp bởi mô-đun 3 44. Mô-đun này cung cấp phương thức "deepcopy", cho phép sao chép toàn bộ hoặc sâu một danh sách tùy ý, tôi. e. nông và các danh sách khác Hãy làm lại ví dụ trước với hàm ['red', 'blue'] ['red', 'blue']0 94400598764928 944005987649601 Sau này, cấu trúc thực hiện trông như thế này Chúng ta có thể thấy rằng danh sách lồng nhau có địa chỉ cũng đã được sao chép Chúng ta có thể thấy bằng cách sử dụng hàm id rằng các danh sách con đã được sao chép, vì ['red', 'blue'] ['red', 'blue']1 khác với ['red', 'blue'] ['red', 'blue']2 94400598764928 944005987649602 ĐẦU RA94400598764928 944005987649603 Một sự thật thú vị là các chuỗi không được sao chép. Chúng ta có thể thấy điều này nếu chúng ta xem ví dụ ở tên ['red', 'blue'] ['red', 'blue']3 và ['red', 'blue'] ['red', 'blue']4. Họ tham chiếu cùng một chuỗi 94400598764928 944005987649604 ĐẦU RA94400598764928 944005987649605 Chúng tôi đã sao chép toàn bộ dữ liệu từ Swen. Vì vậy, tên của người2 vẫn là Sarah. Chúng ta phải đổi nó thành Sarah 94400598764928 944005987649606 Bây giờ nó trông như thế này trong nội bộ, tôi. e. Sarah và Swen sống cùng nhau Vì Sarah đã chuyển đến, chúng tôi hiện đã chuẩn bị kỹ lưỡng cho hành động trốn chạy của cô ấy Bây giờ, đã đến lúc Sara dọn ra ở riêng. 94400598764928 944005987649607 Cô ấy đã chuyển đi thành công và rời bỏ Swen mãi mãi, như chúng ta có thể thấy trong phần sau 94400598764928 944005987649608 ĐẦU RA94400598764928 944005987649609 Để rõ ràng, chúng tôi cũng cung cấp một sơ đồ bao gồm tất cả những thay đổi chúng tôi đã thực hiện sau khi sao chép sâu Chức năng Deepcopy là gì?Deep copy trong Python là gì? . 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 đó điền đệ quy nó 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. creates a new compound object before inserting copies of the items found in the original into it in a recursive manner. It means first constructing a new collection object and then recursively populating it with copies of the child objects found in the original.
Sự khác biệt giữa sao chép copy() và sao chép Deepcopy() là gì?copy() tạo tham chiếu đến đối tượng ban đầu. Nếu bạn thay đổi đối tượng đã sao chép - bạn thay đổi đối tượng ban đầu. . deepcopy() tạo đối tượng mới và sao chép thực sự đối tượng gốc sang đối tượng mới. Thay đổi đối tượng được sao chép sâu mới không ảnh hưởng đến đối tượng gốc
Bản sao () nông hay sâu?Trong Bản sao nông, một bản sao của đối tượng ban đầu được lưu trữ và cuối cùng chỉ có địa chỉ tham chiếu được sao chép. Trong Bản sao sâu, cả bản sao của đối tượng gốc và bản sao lặp lại đều được lưu trữ. 2.
. Sao chép sâu Danh sách () có tạo bản sao sâu không?Bạn không tạo một bản sao sâu bằng list() . |