Python 标准库 copy 深拷贝和浅拷贝

您所在的位置:网站首页 python复制不了 Python 标准库 copy 深拷贝和浅拷贝

Python 标准库 copy 深拷贝和浅拷贝

2024-06-09 13:07| 来源: 网络整理| 查看: 265

本内容来自:https://gairuo.com

说明

《Python 教程》 持续更新中,提供建议、纠错、催更等加作者微信: gairuo123(备注:pandas教程)和关注公众号「盖若」ID: gairuo。跟作者学习,请进入 Python学习课程。欢迎关注作者出版的书籍:《深入浅出Pandas》 和 《Python之光》。

本内容来自:https://gairuo.com

Python 的内置标准库 copy 提供了浅拷贝和深拷贝复制对象的功能, 分别对应模块中的两个函数 copy() 和 deepcopy()。

快速示例

以下是一些示例:

import copy a = [1, 2, ['a', 'b']] # 原对象 b = a # 赋值,传引用 c = copy.copy(a) # 浅拷贝 d = copy.deepcopy(a) # 深拷贝 a.append(3) # 修改对象a a[2][0] = 0 # 修改原对象列表元素中的第一个值 print( '原内容:', a, '# 原对象修改后的值') print( '再赋值:', b, '# 只是引用,就是原对象') print( '浅拷贝:', c, '# 受到对象内部对象的变化,外部的不受影响') print( '深拷贝:', d, '# 不受原对象的变化') ''' 原内容: [1, 2, [0, 'b'], 3] # 原对象修改后的值 再赋值: [1, 2, [0, 'b'], 3] # 只是引用,就是原对象 浅拷贝: [1, 2, [0, 'b']] # 受到对象内部对象的变化,外部的不受影响 深拷贝: [1, 2, ['a', 'b']] # 不受原对象的变化 '''

可以用 https://pythontutor.com/live.html 进行在线测试,观看实时效果。

背景

Python 的赋值语句不复制对象,而是创建目标和对象的绑定关系。对于自身可变,或包含可变项的集合,有时要生成副本用于改变操作,而不必改变原始对象。

浅拷贝(Shallow Copies)

copy() 创建的 浅拷贝 是一个新的容器,它包含了对原始对象的内容的引用。也就是说仅拷贝父对象,不会拷贝对象的内部的子对象。即浅复制只复制对象本身,没有复制该对象所引用的对象。比如,当创建一个列表对象的浅拷贝时,将构造一个新的列表,并将原始对象的元素添加给它。内部元素的变化会影响到原数据和新复制的数据。

深拷贝(Deep Copies)

deepcopy() 创建的 深拷贝 是一个新的容器,它包含了对原始对象的内容的拷贝。深拷贝完全拷贝了父对象及其子对象。即创建一个新的组合对象,同时递归地拷贝所有子对象,新的组合对象与原对象没有任何关联。虽然实际上会共享不可变的子对象,但不影响它们的相互独立性。

总结

总结如下:

由于 Python 内部引用计数的特性,对于不可变对象,浅拷贝和深拷贝的作用是一致的,就相当于复制了一份副本,原对象内部的不可变对象的改变,不会影响到复制对象 浅拷贝的拷贝。其实是拷贝了原始元素的引用(内存地址),所以当拷贝可变对象时,原对象内可变对象的对应元素的改变,会在复制对象的对应元素上,有所体现 深拷贝在遇到可变对象时,又在内部做了新建了一个副本。所以,不管它内部的元素如何变化,都不会影响到原来副本的可变对象

再精减:

直接赋值:其实就是对象的引用(别名)。 浅拷贝(copy):拷贝父对象,不会拷贝对象的内部的子对象,就是说对象的第一层变化不影响新对象的值。 深拷贝(deepcopy): copy 模块的 deepcopy 方法,完全拷贝了父对象及其子对象。 功能

提供的接口有:

copy.copy(x):返回 x 的浅层复制。 copy.deepcopy(x[, memo]):返回 x 的深层复制。 exception copy.Error:针对模块特定错误引发。

浅层与深层复制的区别仅与复合对象(即包含列表或类的实例等其他对象的对象)相关:

浅层复制 构造一个新的复合对象,然后(在尽可能的范围内)将原始对象中找到的对象的 引用 插入其中。 深层复制 构造一个新的复合对象,然后,递归地将在原始对象里找到的对象的 副本 插入其中。

深度复制操作通常存在两个问题, 而浅层复制操作并不存在这些问题:

递归对象 (直接或间接包含对自身引用的复合对象) 可能会导致递归循环。 由于深层复制会复制所有内容,因此可能会过多复制(例如本应该在副本之间共享的数据)。

deepcopy() 函数用以下方式避免了这些问题:

保留在当前复制过程中已复制的对象的 "备忘录" (memo) 字典;以及 允许用户定义的类重载复制操作或复制的组件集合。

此模块不复制诸如模块、方法、堆栈跟踪、堆栈帧、文件、套接字、窗口或任何类似类型的类型。它通过原封不动地返回原始对象来“复制”函数和类(浅层和深层);这与 pickle 模块处理这些问题的方式兼容。

其他

字典的浅层复制可以使用 dict.copy() 方法,而列表的浅层复制可以通过赋值整个列表的切片完成,例如,copied_list = original_list[:]。

类可以使用与控制序列化(pickling)操作相同的接口来控制复制操作,关于这些方法的描述信息请参考 pickle 模块。实际上,copy 模块使用的正是从 copyreg 模块中注册的 pickle 函数。

副本是一个数据的完整的拷贝,如果我们对副本进行修改,它不会影响到原始数据,物理内存不在同一位置。视图是数据的一个别称或引用,通过该别称或引用亦便可访问、操作原有数据,但原有数据不会产生拷贝。如果我们对视图进行修改,它会影响到原始数据,物理内存在同一位置。

有时我们要区分视图是不是只读视图。

自定义拷贝行为

可以通过自定义 _copy__() 和 __deepcopy__() 方法来改变默认的拷贝行为。

__copy()__ 是一个无参数方法,它返回一个浅拷贝对象; __deepcopy()__ 接受一个备忘(memo)字典参数,返回一个深拷贝对象。需要进行深拷贝的成员属性都应该传递给 copy.deepcopy() ,以及memo字典,以控制递归。(下面例子将解释memo字典)。

想要为一个类定义它自己的拷贝操作实现,可以通过定义特殊方法 __copy__() 和 __deepcopy__()。 调用前者以实现浅层拷贝操作;该方法不必传入额外参数。 调用后者以实现深层拷贝操作;它应转入一个参数,即 memo 字典。 如果 __deepcopy__() 实现需要创建一个组件的深层拷贝,它应当调用 deepcopy() 函数并以该组件作为第一个参数而以该 memo 字典作为第二个参数。。 memo 字典应当被当作不透明对象来处理。

参考 https://docs.python.org/zh-cn/3/library/copy.html https://www.cnblogs.com/jhao/p/8656923.html https://zhuanlan.zhihu.com/p/57893374 atexit 退出处理 Python 内置标准库 enum 枚举类型 >

更新时间:2022-06-09 16:43:52 标签:python copy 复制 拷贝



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3