一文搞懂Python中的直接引用、浅拷贝、深拷贝

直接引用

直接引用意味着你创建了一个新的变量,这个变量指向已存在对象的内存地址。

使用方法

# 直接赋值
a = [1, 2, 3]
b = a
id(b) == id(a)

因此,如果你修改了任何一个变量所指向的对象,所有指向该对象的变量都会反映这个改变。

举例说明

a = [1, 2, 3]
b = a  # b是a的直接引用 id(b) == id(a)
b.append(4)  # 修改b
print(a)  # 输出: [1, 2, 3, 4],a也被修改了

浅拷贝

浅拷贝创建了一个新对象,但不会递归地复制对象中的内部对象;它仅仅复制了容器中的元素的引用

使用方法

a = [1, 2, 3]  # 元素不可变
a = [[1, 2], [3, 4]] # 元素可变

# 方法一
b = a[:]  # 或 b = a[0:]

# 方法二
import copy
b = copy.copy(a)
id(b) != id(a)
id(b[0]) ==  id(a[0])

如果容器中的元素是不可变的(比如整数、字符串等),这通常不是问题。但如果容器中包含了可变对象,那么这些对象不会被复制,只是它们的引用被复制了。

举例说明

import copy

a = [[1, 2], [3, 4]]
b = copy.copy(a)  # 浅拷贝a  
b[0].append(5)  # 修改b中的一个子列表
print(a)  # 输出: [[1, 2, 5], [3, 4]],a中的相应子列表也被修改了

深拷贝

深拷贝创建了一个新对象,然后递归地复制了原始对象中的所有元素及其子元素

使用方法

a = [[1, 2], [3, 4]]
import copy
b = copy.deepcopy(a) 
id(b) != id(a)
id(b[0]) !=  id(a[0])

因此,原始对象和新对象完全独立,修改一个不会影响另一个。

举例说明

a = [[1, 2], [3, 4]]
b = copy.deepcopy(a)  # 深拷贝a
b[0].append(5)  # 修改b中的一个子列表
print(a)  # 输出: [[1, 2], [3, 4]],a没有被修改

三种方式如何选择

如果需要拷贝a的是一个一维列表,且其元素(整数)是不可变的,使用浅拷贝(例如 a[:] 或 a[0:])就足够了。这样做能有效地复制列表及其内容,而不需要深拷贝的额外开销。

另外,浅拷贝和深拷贝的概念不限于列表,它们适用于Python中的所有容器类型以及更复杂的对象。这包括但不限于列表、字典、集合以及包含其他对象的自定义类的实例。这两种拷贝方式在处理复合对象(即包含其他对象的对象)时非常重要,因为它们决定了原始数据和新数据之间的独立性。
对于非容器类型的元素(如整数、浮点数、字符串等不可变类型),浅拷贝和深拷贝的效果相同,因为不可变类型不会被“拷贝”——它们是通过引用共享的。

举例说明

考虑一个包含另一个对象作为属性的自定义类。在这种情况下,浅拷贝和深拷贝之间的差异变得尤为重要。

import copy

class MyClass:
    def __init__(self, value):
        self.value = value

class Container:
    def __init__(self, contained):
        self.contained = contained

obj1 = MyClass(10)
container = Container(obj1)

# 浅拷贝
shallow_copied_container = copy.copy(container)
shallow_copied_container.contained.value = 20
print(container.contained.value)  # 输出 20,因为 contained 被浅拷贝,所以它仍然引用原始对象

# 深拷贝
obj2 = MyClass(10)
container = Container(obj2)
deep_copied_container = copy.deepcopy(container)
deep_copied_container.contained.value = 30
print(container.contained.value)  # 输出 10,深拷贝创建了 contained 的一个独立副本

这个例子展示了对于包含其他对象的复杂对象,深拷贝如何能够确保所有层级的数据都被复制,而浅拷贝则只复制最外层的容器。因此,深拷贝和浅拷贝的选择取决于你想要的拷贝深度以及对象之间是否需要独立。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值