Python 深拷贝、浅拷贝

1. 深拷贝和浅拷贝的基本概念和区别

拷贝是计算机科学中一个非常常见的操作,Python中也不例外。在Python中,根据拷贝的程度,可以分为深拷贝和浅拷贝。

深拷贝

深拷贝是指在拷贝源对象的时候,对于原对象中的子对象也进行拷贝,并创建一个相互独立的对象。这样的拷贝操作可以保证拷贝后的对象与源对象没有关联,对拷贝对象的操作不会影响到源对象。

import copy

a = [1, 2, [3, 4]]

b = copy.deepcopy(a)

a[0] = 0

a[2][0] = 0

print(a) # [0, 2, [0, 4]]

print(b) # [1, 2, [3, 4]]

在上面的代码中,我们使用了Python内置的copy模块进行深拷贝,结果显示对于a的修改不会影响到b。

浅拷贝

浅拷贝是指在拷贝源对象的时候,只拷贝原对象的外部引用,并没有对原始对象中的子对象进行拷贝。因此,对拷贝对象进行修改,可能会影响到源对象。

import copy

a = [1, 2, [3, 4]]

b = copy.copy(a)

a[0] = 0

a[2][0] = 0

print(a) # [0, 2, [0, 4]]

print(b) # [1, 2, [0, 4]]

在上面的代码中,我们使用了Python内置的copy模块进行浅拷贝。结果显示对于a的修改同时也影响到了b。

2. Python中的浅拷贝方式

在Python中,可以使用以下方式进行浅拷贝:

切片(Slice)

对于列表、元组、字符串等可迭代对象,可以使用切片实现浅拷贝。切片操作会生成一个新的对象,但是内部元素的引用保持不变,因此如果存在可变的元素,对它们进行修改仍然可能会影响到源对象。

a = [1, 2, [3, 4]]

b = a[:]

a[0] = 0

a[2][0] = 0

print(a) # [0, 2, [0, 4]]

print(b) # [1, 2, [0, 4]]

工厂函数

Python中的一些工厂函数(如list、dict、set等)也可以实现浅拷贝。这些工厂函数会生成一个新的对象,但是如果输入对象中存在子对象,那么生成的新对象中的子对象仍然与原始对象中的子对象共享引用。

a = [1, 2, [3, 4]]

b = list(a)

a[0] = 0

a[2][0] = 0

print(a) # [0, 2, [0, 4]]

print(b) # [1, 2, [0, 4]]

3. Python中的深拷贝方式

在Python中,有多种方式可以实现深拷贝。

使用copy模块的deepcopy函数

在Python中,标准库中的copy模块提供了深拷贝的实现。可以使用copy.deepcopy()函数进行深拷贝。

import copy

a = [1, 2, [3, 4]]

b = copy.deepcopy(a)

a[0] = 0

a[2][0] = 0

print(a) # [0, 2, [0, 4]]

print(b) # [1, 2, [3, 4]]

使用pickle模块

在Python中,标准库中的pickle模块提供了深拷贝的实现。可以使用pickle模块的load()和dump()函数实现深拷贝。

import pickle

a = [1, 2, [3, 4]]

b = pickle.loads(pickle.dumps(a))

a[0] = 0

a[2][0] = 0

print(a) # [0, 2, [0, 4]]

print(b) # [1, 2, [3, 4]]

pickle.dumps()函数将对象转换成了bytes类型,使用pickle.loads()函数将bytes类型的数据转换回对象。

使用copy_reg模块

在Python2.x中,可以使用copy_reg模块实现深拷贝。但是在Python3.x版本中,copy_reg模块已经被废弃。

import copy_reg

import copy

class MyList(list):

def __init__(self, *args, **kwargs):

super(MyList, self).__init__(*args, **kwargs)

self.name = 'MyList'

def pickle_mylist(mylist):

return MyList, tuple(mylist)

copy_reg.pickle(MyList, pickle_mylist)

a = MyList([1, 2, [3, 4]])

b = copy.deepcopy(a)

a[0] = 0

a[2][0] = 0

print(a) # MyList([0, 2, [0, 4]])

print(b) # MyList([1, 2, [3, 4]])

上面的代码使用copy_reg.pickle()函数定义了一个自定义的序列化函数。在使用copy.deepcopy()函数进行深拷贝的时候,会调用这个序列化函数实现深拷贝。

4. 总结

在Python中,拷贝是一个非常常见的操作。根据拷贝的程度,可以分为浅拷贝和深拷贝。浅拷贝只拷贝外部引用,而深拷贝不仅拷贝外部引用,还会将子对象进行拷贝。在Python中可以使用切片、工厂函数、copy模块的deepcopy函数、pickle模块、以及copy_reg模块实现拷贝操作。其中,deepcopy函数是最常用的实现深拷贝的方式,而切片则是实现浅拷贝的一种简单方法。

后端开发标签