0%

Python_浅复制与深复制

流畅的python,Python可视化网站

深复制与浅复制早就有所耳闻,今天发现没有进行相关笔记。这里简单写下,不做深入探讨。

默认为浅复制

浅复制就是仅复制了最外层的引用,而对内部引用不做复制操作;对于不可变元素,这是很好的,减少了内存消耗。然而当内部元素是可变的,就会产生非预期的事情。Python中默认使用浅复制,例如列表中可以采用[:] 与 list() 构造进行复制操作。以下是一段代码,及其内存情况展示,可方便理解,面对不同元素对象操作时的异同。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
l1 = [3, [66,55,44] 
# 通过构造函数进行了浅复制操作
l2 = list(l1) # (1)
l1.append(100) #
l1[1].remove(55) # (2)
print("l1 ,", l1 )
print("l2 ," ,l2)
# l1 , [3, [66, 44], (7, 8, 9), 100]
# l2 , [3, [66, 44], (7, 8, 9)]
l2[1] += [33,22] #(3)
l2[2] += (10 ,11) #(4)
print("l1 ,", l1 )
print("l2 ," ,l2)
# l1 , [3, [66, 44, 33, 22], (7, 8, 9), 100]
# l2 , [3, [66, 44, 33, 22], (7, 8, 9, 10, 11)]

(1)可以看到上图中通过浅复制,l1,l2指向了不同的对象,而对象内部元素的引用并没有变化。

(2)可以看到在对l1中的列表元素进行操作直接影响了l2中列表元素的情况,这当然是由于其内部列表元素指向对象一致,并且列表是可变元素。 可变元素就说明其支持原地修改。

(3)同理,l2中对列表元素的修改,也会影响到l1的内部情况。

(4)需要注意,对l2的tuple元素进行修改操作时,l1,l2不再指向同一tuple,这是由于元组本身不支持就地修改操作,其构建了一个新的元组对象并返回给了l2[2]的位置。

如何进行深浅拷贝

Python提供了copy库方便提供了copy()与deepcopy()方法,很方便。使用方式展示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
"""
>>> import copy
>>> bus1 = Bus(['Alice', 'Bill', 'Claire', 'David'])
>>> bus2 = copy.copy(bus1)
>>> bus3 = copy.deepcopy(bus1)
>>> bus1.drop('Bill')
>>> bus2.passengers
['Alice', 'Claire', 'David']
>>> bus3.passengers
['Alice', 'Bill', 'Claire', 'David']

"""

# BEGIN BUS_CLASS
class Bus:

def __init__(self, passengers=None):
if passengers is None:
self.passengers = []
else:
self.passengers = list(passengers)

def pick(self, name):
self.passengers.append(name)

def drop(self, name):
self.passengers.remove(name)
# END BUS_CLASS

循环引用问题

深拷贝并没有那么简单,例如遇到循环引用时,岂不是会无限copy。不过这不用担心,Python自带的copy库可以记住已经copy过的对象。大胆用。