Python 中的浅拷贝和深拷贝详解

Python 中的浅拷贝与深拷贝详解

转载请注明出处:https://blog.csdn.net/jpch89/article/details/85028862



1. 浅拷贝

1.1 浅拷贝定义

浅拷贝创建了与某对象具有相同值的 另一个对象,即 两个对象的内存地址不同
但是,这两个对象 内部的子对象 仍然是同一个对象,即 内部子对象内存地址相同
简单地说,外层进行了拷贝,内层没有拷贝。

示例如下:

>>> a = [[0, 1], 2, 3]
>>> b = a.copy()  # 浅拷贝
>>> print(id(a))
2266074387336
>>> print(id(b))  # 两个父对象内存地址不同
2266074387464
>>> print(id(a[0]))
2266074385160
>>> print(id(b[0]))  # 内部子对象内存地址相同
2266074385160
>>> b[0][0] = 666
>>> print(a)
[[666, 1], 2, 3]
>>> print(b)
[[666, 1], 2, 3]

浅拷贝与赋值操作的区别在于,赋值语句得到的对象与原来的对象内存地址是相同的。示例如下:

>>> a = [[0, 1], 2, 3]
>>> b = a  # 赋值操作
>>> c = a.copy()  # 浅拷贝
>>> print(id(a))
2266074385160
>>> print(id(b))
2266074385160
>>> print(id(c))
2266074387592

1.2 浅拷贝实现

以下方式得到的拷贝都是浅拷贝:

  • 切片操作 [:]
  • 调用列表、字典、集合的方法 copy()
  • 调用内置函数 list()dict()set()
  • 调用标准库模块 copy 中的函数 copy()

示例如下:

>>> a = [[0, 1], 2, 3]
>>> b = a[:]
>>> c = a.copy()
>>> d = list(a)
>>> e = copy.copy(a)
>>> print(id(a))
2266074385160
>>> print(id(b))
2266074385800
>>> print(id(c))
2266074385608
>>> print(id(d))
2266074388168
>>> print(id(e))
2266075822792
>>> print(id(a[0]))
2266074387464
>>> print(id(b[0]))
2266074387464
>>> print(id(c[0]))
2266074387464
>>> print(id(d[0]))
2266074387464
>>> print(id(e[0]))
2266074387464

2. 深拷贝

2.1 深拷贝定义

深拷贝创建了与某对象具有相同值的 另一个对象,即 两个对象的内存地址不同

注解:由此可见,拷贝 这一术语就意味着在内存当中创建原始数据的副本,该副本与原始数据占据不同的内存空间。

同时,这两个对象内部对应的 可变 子对象不是同一个对象,即 可变 子对象的内存地址不同。
简单的说,外层和内层都进行了拷贝。


2.2 深拷贝实现

可以调用标准库模块 copy 中的函数 deepcopy() 实现深拷贝。
示例如下:

>>> a = [[0, 1], 2, 3]
>>> b = copy.deepcopy(a)
>>> print(id(a))
2266074387464
>>> print(id(b))
2266074388168
>>> print(id(a[0]))
2266074385160
>>> print(id(b[0]))
2266075885832

3. 不可变对象的深浅拷贝

  • 对于没有嵌套子对象的不可变对象,例如:整数对象、字符串对象和元组对象等,不会进行拷贝(不论是浅拷贝还是深拷贝)。也就是说,不会创建另一个对象,内存地址保持不变,即 深浅拷贝都等同于赋值操作。示例如下:
    >>> a = (1, 2, '3')
    >>> b = copy.copy(a)
    >>> c = copy.deepcopy(a)
    >>> print(id(a))
    2266074328016
    >>> print(id(b))
    2266074328016
    >>> print(id(c))
    2266074328016
    
  • 对于有嵌套子对象的不可变对象,如果子对象是 不可变的,不会进行拷贝,也就是说,不会创建另一个对象,内存地址保持不变,即 深浅拷贝都等同于赋值操作
    >>> a = ((0, 1), 2, 3)
    >>> b = copy.copy(a)
    >>> c = copy.deepcopy(a)
    >>> print(id(a))
    2266074328016
    >>> print(id(b))
    2266074328016
    >>> print(id(c))
    2266074328016
    >>> print(id(a[0]))
    2266074460680
    >>> print(id(b[0]))
    2266074460680
    >>> print(id(c[0]))
    2266074460680
    
  • 对于有嵌套子对象的不可变对象,如果子对象是 可变的,浅拷贝不会创建另一个对象,内存地址保持不变,即 浅拷贝等同于赋值操作。而深拷贝会创建另一个对象,内存地址改变。
    # 浅拷贝
    >>> a = ([0, 1], 2, 3)
    >>> b = a[:]
    >>> c = copy.copy(a)
    >>> d = tuple(a)
    >>> print(id(a))
    2266074327656
    >>> print(id(b))
    2266074327656
    >>> print(id(c))
    2266074327656
    >>> print(id(d))
    2266074327656
    >>> print(id(a[0]))
    2266075822856
    >>> print(id(b[0]))
    2266075822856
    >>> print(id(c[0]))
    2266075822856
    >>> print(id(d[0]))
    2266075822856
    # 深拷贝
    >>> e = copy.deepcopy(a)
    >>> print(id(a))
    2266074327656
    >>> print(id(e))
    2266074507880
    >>> print(id(a[0]))
    2266075822856
    >>> print(id(e[0]))
    2266074385608
    

完成于 2018.12.16

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值