Python 浅复制与深复制的区别
类是定义对象属性(数据)和行为(方法)的蓝图或模板。这是面向对象编程(OOP)的一个基本概念,允许你基于类定义创建项目。
浅复制
浅复制创建一个存储原始元素引用的新对象。它不会复制嵌套对象,只是复制它们的引用。这意味着复制过程不会递归或自行创建嵌套对象的副本。浅复制比深复制快,但是它对指针和引用进行处理。
它只会复制指针值,而不是创建指针所链接的具体信息的新副本。因此,原始和副本都将有指向相同底层数据的指针。
浅复制通常使用内置的copy.copy()方法或复制构造函数执行。
深复制
深复制创建一个存储原始元素副本的新对象。它与原始对象和副本对象之间不共享。深复制实际上是克隆底层数据。它与原始对象和副本对象之间不共享。深复制比浅复制慢,但它创建的是对象及其所有子对象的完整副本。
可以使用copy模块提供的copy.deepcopy()方法来实现深复制。
示例
在这个示例中,我们将创建一个类的实例,并进行浅复制和深复制,以了解复制过程的工作原理以及它如何影响内部对象的内存地址。
import copy
class MyClass:
def __init__(self, name, numbers):
self.name = name
self.numbers = numbers
def __repr__(self):
return f"MyClass(name='{self.name}', numbers={self.numbers})"
# Creating an instance of MyClass
original_obj = MyClass("Rahul Ravindranath", [53, 27, 82])
print("Memory address of original_obj.name:", id(original_obj.name))
print("Memory address of original_obj.numbers:", id(original_obj.numbers))
# Making a shallow copy
shallow_copy = copy.copy(original_obj)
# Checking memory addresses of internal objects for shallow copy
print("Memory address of shallow_copy.name:", id(shallow_copy.name))
print("Memory address of shallow_copy.numbers:", id(shallow_copy.numbers))
# Creating a Deep copy
deep_copy = copy.deepcopy(original_obj)
# Checking memory addresses of internal objects for deep copy
print("Memory address of deep_copy.name:", id(deep_copy.name))
print("Memory address of deep_copy.numbers:", id(deep_copy.numbers))
输出
Memory address of original_obj.name: 23317216835824
Memory address of original_obj.numbers: 23317215777984
Memory address of shallow_copy.name: 23317216835824
Memory address of shallow_copy.numbers: 23317215777984
Memory address of deep_copy.name: 23317216835824
Memory address of deep_copy.numbers: 23317215706944
需要注意的是,不同设备的内存地址是不同的。
从上述输出中,我们可以推断浅拷贝的内存地址和原始对象中相应属性的内存地址相同。这表明内部对象并没有被复制,而是被引用。
当我们检查深拷贝的内存地址时,发现它们与原始对象中相应属性的内存地址不同。这表明内部对象已经被复制,为深拷贝创建了单独的实例。
示例
在这段代码中,我们将创建一个类,并创建其浅拷贝和深拷贝,然后使用一些操作修改拷贝,并演示原始对象及其拷贝的更改。
步骤
- 定义一个名为ClassEx的类,其中包含一个init方法,用于初始化一个具有name属性和空列表属性的实例。
-
实现一个add_item和str方法,用于向列表中添加项并提供实例的字符串表示。
-
创建一个名为original的ClassEx实例。
-
使用add_item方法向original及其拷贝中添加所需数据。
-
显示“original”实例及其浅拷贝和深拷贝。
-
通过使用列表属性和索引,在每个对象中替换一些项,包括原始对象、浅拷贝和深拷贝。
-
打印更新后的原始对象、浅拷贝和深拷贝。
import copy
class ClassEx:
def __init__(self, name):
self.name = name
self.list = []
def add_item(self, item):
self.list.append(item)
def __str__(self):
return f"{self.name}: {self.list}"
# Create an instance of ClassEx
original = ClassEx("Original")
# Add some items to the list
original.add_item("Item 1")
original.add_item("Item 2")
# Create a shallow copy of the object
shallow_copy = copy.copy(original)
# Add an item to the list of the shallow copy
shallow_copy.add_item("Item 3")
# Print the original object and the shallow copy
print("Original object:", original)
print("Shallow copy:", shallow_copy)
# Create a deep copy of the object
deep_copy = copy.deepcopy(original)
# Add an item to the list of the deep copy
deep_copy.add_item("Item 4")
# Print the original object and the deep copy
print("Original object:", original)
print("Deep copy:", deep_copy)
# Replace an item in the original object
original.list[0] = "New Item 1"
# Replace an item in the shallow copy
shallow_copy.list[1] = "New Item 2"
# Replace an item in the deep copy
deep_copy.list[2] = "New Item 3"
# Print the updated objects
print("Original object:", original)
print("Shallow copy:", shallow_copy)
print("Deep copy:", deep_copy)
输出
Original object: Original: ['Item 1', 'Item 2', 'Item 3']
Shallow copy: Original: ['Item 1', 'Item 2', 'Item 3']
Original object: Original: ['Item 1', 'Item 2', 'Item 3']
Deep copy: Original: ['Item 1', 'Item 2', 'Item 3', 'Item 4']
Original object: Original: ['New Item 1', 'New Item 2', 'Item 3']
Shallow copy: Original: ['New Item 1', 'New Item 2', 'Item 3']
Deep copy: Original: ['Item 1', 'Item 2', 'New Item 3', 'Item 4']
浅拷贝与原始对象共享内部对象,而深拷贝创建内部对象的独立副本。在浅拷贝和原始对象中进行的更改相互影响,而深拷贝完全分离,当在深拷贝中进行修改时不会影响原始对象。
主要区别
项目 | 浅拷贝 | 深拷贝 |
---|---|---|
内存共享 | 与原始对象共享内存位置 | 创建一个独立的副本,具有独立的内存位置 |
性能 | 更快、更高效,特别适用于大型对象或复杂的数据结构 | 较慢,可能消耗更多的内存,尤其是对于大型对象或深层嵌套的情况 |
数据完整性 | 可能导致意外修改原始对象 | 通过隔离拷贝的对象来确保数据完整性 |
对复制对象的更改 | 修改可能会影响原始对象,反之亦然 | 修改不会影响原始对象 |
依赖和引用 | 共享引用可能导致意外的副作用或数据完整性问题 | 通过复制所有嵌套对象来处理循环引用和复杂的依赖关系 |
结论
浅拷贝用于创建对象当前状态的备份或快照。当实现写时拷贝行为,即只有在对拷贝的对象进行更改时才进行拷贝,并且用现有对象的初始值创建新对象时,使用浅拷贝。
深拷贝用于创建一个完全独立的对象及其嵌套对象的拷贝。对于对象的序列化和反序列化,需要独立存储或传输拷贝的对象时,深拷贝非常有帮助。