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

猜你喜欢

转载自blog.csdn.net/jpch89/article/details/85028862