Python improvement study notes (1): deep copy and shallow copy

1. What is an object reference?

In Python, an object reference refers to the address or identifier of a variable pointing to an object in memory. When you create a new object (such as an integer, string, list, etc.), Python will allocate a memory to store the object and assign a unique identifier to the object (that is, the address of the object). When you assign this object to a variable, the variable actually stores a reference to the object, not the object itself. This means that the variable does not directly contain the value of the object, but points to the memory address where this value is stored.

Example:

In [19]: x = [1, 2, 3] # 创建一个列表对象,并将其引用赋给变量x
In [20]: y = x # y和x现在指向同一个列表对象
In [21]: # 修改x所指向的列表对象
In [22]: x.append(4)
In [23]: print(y) # 输出[1, 2, 3, 4],因为y引用的是和x相同的列表对象
[1, 2, 3, 4]

In this example, [1, 2, 3] is a list object with its own address in memory. The x variable contains a reference to the list object, not the list object itself. If you create a new variable y = x, then y will actually point to the same list object as well, i.e. they share the same reference. Illustration:
Insert image description here
Therefore, For mutable objects (such as lists, dictionaries, etc.), If multiple variables refer to For the same object, when you modify the object through a variable, other variables that reference the same object will also reflect the modification. This is because they refer to the same object, not copies of the object. For immutable objects (such as integers, strings, etc.), Since the object itself is immutable, any modification will result in the creation of a new object without Will affect the original object, because modifications to an immutable object actually create a new object and repoint the variable to the address of the new object. Example:

In [33]: x = 300
In [34]: y = x
In [35]: y = 400
In [36]: print(x, y)
300 400

Illustration:
Insert image description here
Supplement: In Python, == and is are operators used to compare objects, but their functions are different:

The == operator is used to compare whether the values ​​of two objects are equal.
The is operator is used to check whether two objects are the same object, that is, to compare whether their identities (i.e. memory addresses/references) are the same. . Examples include:

In [39]: a = [1, 2, 3]
In [40]: b = [1, 2, 3]
In [41]: # 比较值是否相等
In [42]: print(a == b) # 输出True,因为列表a和列表b中的元素都相同
True
In [43]: # 检查是否是同一个对象
In [44]: print(a is b) # 输出False,因为a和b是不同的对象,即在内存地址/引用不一样
False

Note: In Python, there is a specific mechanism for caching small integer objects within a certain range, which is usually -5~256 ( This range may vary slightly depending on Python version and implementation). This means that integer objects in this range will be cached and reused during the lifetime of the Python program, rather than creating new objects each time. This caching mechanism is to improve performance and save memory. Because these small integers are commonly used in many situations, Python will pre-create these objects at startup and cache them. When you need to use these integers, Python will directly return the objects in the cache instead of creating new objects. This caching mechanism makes it possible for the is operator to return True when comparing integer objects in the same range because they point to the same object:

In [45]: x = 10
In [46]: y = 10
In [47]: print(x is y) # 输出True,因为x和y是同一个对象,由于小整数的缓存机制(有些也称为常量池)
True
In [48]: a = 300
In [49]: b = 300
In [50]: print(a is b) # 输出False,因为超出了小整数的缓存范围,a和b是不同的对象
False

2. Deep copy and shallow copy

In Python, deep copy and shallow copy are concepts used to create copies of objects. Before understanding the difference between the two, let’s take a look at their definition and usage.

2.1 Shallow Copy

A shallow copy creates a new object, but only copies a reference to the object. This means that the original object and its copy refer to the same sub-object. When you make changes to the original or copy object, changes to the child objects are reflected between the two.

In Python, you can use the copy() method in the copy module to perform shallow copies:

In [65]: import copy
In [66]: original_list = [1, 2, [3, 4]]
In [67]: new_list = original_list  # 赋值是最简单的浅拷贝
In [68]: id(original_list) # 用来显示original_list指向的数据的内存地址
Out[68]: 1837971633856
In [69]: id(new_list) # 用来显示new_list指向的数据的内存地址
Out[69]: 1837971633856

In [70]: shallow_copied_list = copy.copy(original_list)
In [71]: # 修改shallow_copied_list副本中的元素
In [72]: shallow_copied_list[0] = 5
In [73]: # 修改子对象(原始对象和副本对象共享的对象)
In [74]: shallow_copied_list[2][0] = 6
In [77]: print(original_list, new_list)
[1, 2, [6, 4]] [1, 2, [6, 4]]
In [78]: print(shallow_copied_list)
[5, 2, [6, 4]]

Image:
Insert image description here
Dictionary example:

In [131]: import copy
In [132]: d = dict(name='AmoXiang',age=19,hobby_list=['dance', 'sing'])
In [133]: co = copy.copy(d)
In [134]: d
Out[134]: {
    
    'name': 'AmoXiang', 'age': 19, 'hobby_list': ['dance', 'sing']}
In [135]: co
Out[135]: {
    
    'name': 'AmoXiang', 'age': 19, 'hobby_list': ['dance', 'sing']}
In [136]: id(d),id(co)
Out[136]: (1838005229056, 1838001691136)
In [137]: d['name'] = 'Amo'
In [138]: d
Out[138]: {
    
    'name': 'Amo', 'age': 19, 'hobby_list': ['dance', 'sing']}
In [139]: co
Out[139]: {
    
    'name': 'AmoXiang', 'age': 19, 'hobby_list': ['dance', 'sing']}
In [140]: co['hobby_list'].append('swim')
In [141]: co
Out[141]: {
    
    'name': 'AmoXiang', 'age': 19, 'hobby_list': ['dance', 'sing', 'swim']}
In [142]: d
Out[142]: {
    
    'name': 'Amo', 'age': 19, 'hobby_list': ['dance', 'sing', 'swim']}
In [143]: id(d['name']),id(co['name'])
Out[143]: (1837976233200, 1837949658800)
In [144]: id(d['age']),id(co['age'])
Out[144]: (1837896002416, 1837896002416)
In [145]: id(d['hobby_list']),id(co['hobby_list'])
Out[145]: (1837979180480, 1837979180480)
In [146]: co['age'] = 20
In [147]: co
Out[147]: {
    
    'name': 'AmoXiang', 'age': 20, 'hobby_list': ['dance', 'sing', 'swim']}
In [148]: d
Out[148]: {
    
    'name': 'Amo', 'age': 19, 'hobby_list': ['dance', 'sing', 'swim']}

Shallow copy copies immutable types and variable types differently:
copy.copy For variable types, a shallow copy will be performed
copy.copy For immutable types, there will be no copy, only pointers

In [159]: import copy
In [160]: a = [1,2,3]
In [161]: b = copy.copy(a)
In [162]: id(a),id(b)
Out[162]: (1838001649984, 1837979060672)
In [163]: a.append(4)
In [164]: a
Out[164]: [1, 2, 3, 4]
In [165]: b
Out[165]: [1, 2, 3]
In [166]: a = (1,2,3)
In [167]: b = copy.copy(a)
In [168]: id(a),id(b)
Out[168]: (1838005603584, 1838005603584)

2.2 Deep Copy

A deep copy creates a completely new object while recursively copying all child objects. This means that the original object and its copy do not share any child objects. Whatever changes you make to the original object or the copy will not affect the other. Also use the deepcopy() method in the copy module to perform a deep copy:

In [90]: import copy
In [91]: original_list = [1, 2, [3, 4]]
In [92]: deep_copied_list = copy.deepcopy(original_list)
In [93]: id(original_list)
Out[93]: 1838005694912
In [94]: id(deep_copied_list)
Out[94]: 1838005773312
In [95]: # 修改副本的元素
In [96]: deep_copied_list[0] = 5
In [97]: # 修改子对象(原始对象和副本对象共享的对象)
In [98]: deep_copied_list[2][0] = 6
In [99]: print(original_list)  # 输出:[1, 2, [3, 4]]
[1, 2, [3, 4]]
In [100]: print(deep_copied_list)  # 输出:[5, 2, [6, 4]]
[5, 2, [6, 4]]
In [101]: print(id(original_list[2]))
1838004780096
In [102]: print(id(deep_copied_list[2]))
1838001793984

Illustration:
Insert image description here

2.3 The difference between copy.copy and copy.deepcopy

copy.copy Illustration:
Insert image description here
copy.deepcopy If you are interested, you can draw it yourself. I will not go into details here (the picture is too difficult to draw, so I am lazy).

Guess you like

Origin blog.csdn.net/xw1680/article/details/134547412