python中copy模块的使用,深拷贝和浅拷贝

简介: python中copy模块的使用,深拷贝和浅拷贝

一、copy模块的介绍

1、copy模块

copy模块用于对象的拷贝操作。copy模块非常简单,只有两个api。分别是copy.copy(x)和copy.deepcopy(x)。这两个函数分别返回参数x的浅复制和深复制。该模块只提供了两个主要的方法:

  • copy.copy:浅复制(Shallow copy)
  • copy.deepcopy:深复制(Deep copy)

#

二、copy模块的使用

  • copy仅拷贝对象本身,而不对其中的子对象进行拷贝,故对子对象进行修改也会随着修改。(例如下面的:[1,2,3, [2,3],4] 其中[2,3] 就是子对象)
  • deepcopy是真正意义上的复制,即从新开辟一片空间。我们经常说的复制实际上就是deepcopy.(深拷贝之后的对象是不受原对象的影响,无论原对象发生什么修改,深拷贝的对象都不会发生改变
>>> import copy
>>> a = [1,2,3, [2,3],4]
>>> b = a
>>> c = copy.copy(a)
>>> c
[1, 2, 3, [2, 3], 4]
>>>
>>> b
[1, 2, 3, [2, 3], 4]
>>> d = copy.deepcopy(a)
>>> d
[1, 2, 3, [2, 3], 4]
>>> a[3][0]=222
>>> a
[1, 2, 3, [222, 3], 4]
>>> b
[1, 2, 3, [222, 3], 4]
>>> c
[1, 2, 3, [222, 3], 4]
>>> d
[1, 2, 3, [2, 3], 4]
  1. 复制引用

在Python里,一切皆对象。当用赋值运算符将某个对象x赋值给另外一个对象y时,仅仅只是将x的引用赋值给y。本质上x和y指向的是同一块内存区域。这里可以使用Python的内建函数id()进行验证:

x = [1, 2, 3]
y = x
print(id(x) == id(y)) # True
  1. 克隆对象

如果想要对目标进行克隆,而不是简单的引用绑定,就需要用到copy模块。使用copy模块可以创建一个与原对象一模一样的新对象。

import copy
x = [1, 2, 3]
y = copy.copy(x)
print(id(x) == id(y)) # False
  1. 克隆策略

当对象x里面包含了另外一个对象z,甚至对象z里面包含了对象a、对象b、对象c。情况就变得复杂了。这个时候有两种策略可以选择:

  • 仅仅创建一个新对象y,而y里面的对象z,通过复制引用绑定到同一个对象上。
  • 递归地克隆目标对象及目标对象中包含的其他对象。

这两种策略,就对应了copy模块里面的copy()和deepcopy()。

使用浅复制策略时:

import copy
x = [[1, 2, 3]]
y = copy.copy(x)
print(id(x) == id(y)) # False
print(id(x[0]) == id(y[0])) # True    浅拷贝,并没有改变子对象的

使用深复制策略时:

import copy
x = [[1, 2, 3]]
y = copy.deepcopy(x)
print(id(x) == id(y)) # False
print(id(x[0]) == id(y[0])) # False

简单的说就是有没有递归调用的区别。

可以看出,深复制更加彻底,可以由里到外创建一个完完全全的新对象而不受原对象影响。但这也会导致一些问题的出现:

  • 对于某些过于复杂的对象,深复制可能会严重拖累程序的运行。
  • 某些共享数据并不需要复制,深复制会导致不同对象之间不同步。

当然,deepcopy()函数也使用了一些方法避免以上情况的出现:

  • 维护一个“memo”字典,保存当前复制操作已经复制过的对象。
  • 允许用户自定义克隆策略。

至于选择哪种克隆策略,还是要具体问题具体分析。

  1. 自定义克隆策略

用户自定义的类允许重写copy和deepcopy函数,这样就可以自定义调用copy模块时的操作,自行调整克隆策略:

import copy

class a():
    # 重写copy函数无法额外参数
    def __copy__(self):
        return "override copy"

    # 重写deepcopy函数需要一个额外参数,字典类型
    def __deepcopy__(self, memo):
        return "override deepcopy"

x = a()
print(copy.copy(x)) # override copy
print(copy.deepcopy(x)) # override deepcopy
  1. 其他需要注意的地方
  • copy模块无法复制诸如:type、函数、stack trace、stack frame、file、socket、window、array等类型。调用copy模块复制上述类型的对象会返回原对象或者直接报错。

  • 字典的浅复制可以使用y = x.copy()。而列表可以通过使用切片达到同样的目的y = x[:]

拓展说明:

1、id( )函数的使用

python中会为每个对象分配内存,哪怕他们的值完全相等。id(object)函数是返回对象object在其生命周期内位于内存中的地址,id函数的参数类型是一个对象。

2、is和== 的区别

用is判断两个对象是否相等时,依据就是这个id值。
is与\==的区别就是,is是内存中的比较,而\==是值的比较

目录
相关文章
|
23天前
|
开发者 Python
如何在Python中管理模块和包的依赖关系?
在实际开发中,通常会结合多种方法来管理模块和包的依赖关系,以确保项目的顺利进行和可维护性。同时,要及时更新和解决依赖冲突等问题,以保证代码的稳定性和可靠性
42 4
|
3天前
|
Python
Python Internet 模块
Python Internet 模块。
99 74
|
21天前
|
算法 数据安全/隐私保护 开发者
马特赛特旋转算法:Python的随机模块背后的力量
马特赛特旋转算法是Python `random`模块的核心,由松本真和西村拓士于1997年提出。它基于线性反馈移位寄存器,具有超长周期和高维均匀性,适用于模拟、密码学等领域。Python中通过设置种子值初始化状态数组,经状态更新和输出提取生成随机数,代码简单高效。
103 63
|
23天前
|
测试技术 Python
手动解决Python模块和包依赖冲突的具体步骤是什么?
需要注意的是,手动解决依赖冲突可能需要一定的时间和经验,并且需要谨慎操作,避免引入新的问题。在实际操作中,还可以结合使用其他方法,如虚拟环境等,来更好地管理和解决依赖冲突😉。
|
23天前
|
持续交付 Python
如何在Python中自动解决模块和包的依赖冲突?
完全自动解决所有依赖冲突可能并不总是可行,特别是在复杂的项目中。有时候仍然需要人工干预和判断。自动解决的方法主要是提供辅助和便捷,但不能完全替代人工的分析和决策😉。
|
29天前
|
JSON Linux 数据格式
Python模块:从入门到精通,只需一篇文章!
Python中的模块是将相关代码组织在一起的单元,便于重用和维护。模块可以是Python文件或C/C++扩展,Python标准库中包含大量模块,如os、sys、time等,用于执行各种任务。定义模块只需创建.py文件并编写代码,导入模块使用import语句。此外,Python还支持自定义模块和包,以及虚拟环境来管理项目依赖。
Python模块:从入门到精通,只需一篇文章!
|
23天前
|
Python
Python的模块和包
总之,模块和包是 Python 编程中非常重要的概念,掌握它们可以帮助我们更好地组织和管理代码,提高开发效率和代码质量
37 5
|
23天前
|
数据可视化 Python
如何在Python中解决模块和包的依赖冲突?
解决模块和包的依赖冲突需要综合运用多种方法,并且需要团队成员的共同努力和协作。通过合理的管理和解决冲突,可以提高项目的稳定性和可扩展性
|
1月前
|
Python
在Python中,可以使用内置的`re`模块来处理正则表达式
在Python中,可以使用内置的`re`模块来处理正则表达式
43 5
|
1月前
|
Java 程序员 开发者
Python的gc模块
Python的gc模块