ITmob-Ly
发布于 2024-03-28 / 100 阅读
0

Python 基础:对 Python 中深拷贝和浅拷贝的理解

Python 中对象的赋值、拷贝之间是有区别的。

  • 对象的赋值是进行对象引用的传递
    • 赋值后两个变量都指向同一个内存中的对象,对任一个的修改都会体现到其他引用上。
  • 拷贝有深拷贝、浅拷贝之分。
    • copy.copy(obj) & copy.deepcopy(obj)

copy & deepcopy

深拷贝、浅拷贝 由 copy 模块提供

下面是 copy 模块的 Docstrings 中对 copy、deepcopy 的描述:

NAME
        copy - Generic (shallow and deep) copying operations.

DESCRIPTION
	    Interface summary:

        import copy

        x = copy.copy(y)        # make a shallow copy of y
        x = copy.deepcopy(y)    # make a deep copy of y

The difference between shallow and deep copying is only relevant for compound objects (objects that contain other objects, like lists or class instances).

- A shallow copy constructs a new compound object and then (to the extent possible/尽可能) inserts *the same objects* into it that the original contains.
- A deep copy constructs a new compound object and then, recursively(递归地),inserts *copies* into it of the objects found in the original.

Two problems often exist with deep copy operations that don't exist with shallow copy operations:

a) recursive objects (compound objects that, directly or indirectly, contain a reference to themselves) my cause a recursive loop.

b) because deep copy copies *everything* it may copy too much, e.g. administrative(管理的,行政的) data structures that should be shared even between copies.

Python's deep copy operation avoids these problems by:

a) keeping a table of objects already copied during the current copying pass

b) letting user-defined class override the copying operation or the set of components copied.(允许用户定义的类重写复制操作或复制的组件集)

对 Docstrings 的理解:

  • 浅拷贝、深拷贝只与符合对象有关
    • 深浅拷贝对int bool 元组等原子类型的操作相同,不复制指向相同内存,但对任何一方的修改都会重新创建,互不影响
    • 只对复合对象的操作不同,浅拷贝不复制复合对象,还是指向同一块内存,任何修改都相互影响。深拷贝会递归复制所有包含的复合对象,不再相互影响
  • 浅拷贝只是创建一个新的复合对象,而对象中的对象依然是指向源数据
  • 深拷贝,会创建一个新对象,然后对对象中的内容递归的复制。复制后两个对象互不再影响

理解 浅拷贝、深拷贝:

>>> a = [1,2]
>>> b = [3,4]
>>> c = (a,b)
>>> d = copy.copy(c)
# 浅拷贝与原子类型无关
>>> id(c)
2525683132296
>>> id(d)
2525683132296

# 浅拷贝不会递归对对象中的复合对象复制
>>> d[0][0] = 5
>>> d
([5,2], [3,4])
>>> c
([5,2], [3,4])

>>> a = [1,2,[3,4]]
>>> b = copy.copy(a)
# 浅拷贝复制了最外层复合对象
>>> id(a)
2525679869832
>>> id(b)
2525679869448
# 浅拷贝不会对原子类型复制(a=1;b=copy.copy(a)也不会复制依然是指向相同地址)
>>> id(a[0])
2525679943824
>>> id(b[0])
2525679943824
# 浅拷贝不复制原子类型,但修改原子类型时,会重新创建一份修改
# 浅拷贝后,对原子类型的修改不会相互影响
>>> b[0] = 5
>>> b
[5, 2, [3, 4]]
>>> a
[1, 2, [3, 4]]
# 浅拷贝后,复合类型的修改会相互影响
>>> b[2][0] = 6
>>> b
[5, 2, [6, 4]]
>>> a
[1, 2, [6, 4]]

>>> a = 1
>>> b = copy.deepcopy(a)
# 深拷贝、浅拷贝的区别,只与对复合对象的处理相关
# 深拷贝也不会复制原子类型
>>> id(a)
1846767027
>>> id(b)
1846767027
# 与浅拷贝一样,对原子类型的修改也是重新创建,不相互影响
>>> b = 2
>>> a
1
>>> b
2