Python FAQ2:赋值、浅拷贝、深拷贝的区别?

发表于 2014-08-15   |   分类于 Lang.-Python  |  

在写Python过程中,经常会遇到对象的拷贝,如果不理解浅拷贝深拷贝的概念,你的代码就可能出现一些问题。所以,在这里按个人的理解谈谈它们之间的区别。

一、赋值(assignment)

在《Python FAQ1》一文中,对赋值已经讲的很清楚了,关键要理解变量与对象的关系

1
2
3
4
5
>>> a = [1, 2, 3]
>>> b = a
>>> print(id(a), id(b), sep='\n')
139701469405552
139701469405552

在Python中,用一个变量给另一个变量赋值,其实就是给当前内存中的对象增加一个“标签”而已。

如上例,通过使用内置函数 id() ,可以看出 a 和 b 指向内存中同一个对象。a is b会返回 True 。

二、浅拷贝(shallow copy)

注意:浅拷贝和深拷贝的不同仅仅是对组合对象来说,所谓的组合对象就是包含了其它对象的对象,如列表,类实例。而对于数字、字符串以及其它“原子”类型,没有拷贝一说,产生的都是原对象的引用。

所谓“浅拷贝”,是指创建一个新的对象,其内容是原对象中元素的引用。(拷贝组合对象,不拷贝子对象)

常见的浅拷贝有:切片操作、工厂函数、对象的copy()方法、copy模块中的copy函数。

1
2
3
4
5
6
7
8
9
10
>>> a = [1, 2, 3]
>>> b = list(a)
>>> print(id(a), id(b)) # a和b身份不同
140601785066200 140601784764968
>>> for x, y in zip(a, b): # 但它们包含的子对象身份相同
... print(id(x), id(y))
...
140601911441984 140601911441984
140601911442016 140601911442016
140601911442048 140601911442048

从上面可以明显的看出来,a 浅拷贝得到 b,a 和 b 指向内存中不同的 list 对象,但它们的元素却指向相同的 int 对象。这就是浅拷贝!

三、深拷贝(deep copy)

所谓“深拷贝”,是指创建一个新的对象,然后递归的拷贝原对象所包含的子对象。深拷贝出来的对象与原对象没有任何关联。

深拷贝只有一种方式:copy模块中的deepcopy函数。

1
2
3
4
5
6
7
8
9
10
11
>>> import copy
>>> a = [1, 2, 3]
>>> b = copy.deepcopy(a)
>>> print(id(a), id(b))
140601785065840 140601785066200
>>> for x, y in zip(a, b):
... print(id(x), id(y))
...
140601911441984 140601911441984
140601911442016 140601911442016
140601911442048 140601911442048

看了上面的例子,有人可能会疑惑:

为什么使用了深拷贝,a和b中元素的id还是一样呢?

答:这是因为对于不可变对象,当需要一个新的对象时,python可能会返回已经存在的某个类型和值都一致的对象的引用。而且这种机制并不会影响 a 和 b 的相互独立性,因为当两个元素指向同一个不可变对象时,对其中一个赋值不会影响另外一个。

我们可以用一个包含可变对象的列表来确切地展示“浅拷贝”与“深拷贝”的区别:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
>>> import copy
>>> a = [[1, 2],[5, 6], [8, 9]]
>>> b = copy.copy(a) # 浅拷贝得到b
>>> c = copy.deepcopy(a) # 深拷贝得到c
>>> print(id(a), id(b)) # a 和 b 不同
139832578518984 139832578335520
>>> for x, y in zip(a, b): # a 和 b 的子对象相同
... print(id(x), id(y))
...
139832578622816 139832578622816
139832578622672 139832578622672
139832578623104 139832578623104
>>> print(id(a), id(c)) # a 和 c 不同
139832578518984 139832578622456
>>> for x, y in zip(a, c): # a 和 c 的子对象也不同
... print(id(x), id(y))
...
139832578622816 139832578621520
139832578622672 139832578518912
139832578623104 139832578623392

从这个例子中可以清晰地看出浅拷贝与深拷贝地区别。

总结:

1、赋值:简单地拷贝对象的引用,两个对象的id相同。
2、浅拷贝:创建一个新的组合对象,这个新对象与原对象共享内存中的子对象。
3、深拷贝:创建一个新的组合对象,同时递归地拷贝所有子对象,新的组合对象与原对象没有任何关联。虽然实际上会共享不可变的子对象,但不影响它们的相互独立性。

浅拷贝和深拷贝的不同仅仅是对组合对象来说,所谓的组合对象就是包含了其它对象的对象,如列表,类实例。而对于数字、字符串以及其它“原子”类型,没有拷贝一说,产生的都是原对象的引用。

源自:https://songlee24.github.io/2014/08/15/python-FAQ-02/

python copy和deepcopy的更多相关文章

  1. python copy与deepcopy (拷贝与深拷贝)

    copy与deepcopy python 中的copy与deepcopy是内存数据的操作,但是两个函数有一定的区别. 1.copy import copy list = [1, [4, 5, 6], ...

  2. Python copy and deepcopy

    Python中的对象之间赋值时是按引用传递的,如果需要拷贝对象,需要使用标准库中的copy模块. 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象. 2. copy.deep ...

  3. 从python中copy与deepcopy的区别看python引用

    讨论copy与deepcopy的区别这个问题要先搞清楚python中的引用.python的内存管理. python中的一切事物皆为对象,并且规定参数的传递都是对象的引用.可能这样说听起来比较难懂,对比 ...

  4. Python的传值和传址与copy和deepcopy

    1.传值和传址 传值就是传入一个参数的值,传址就是传入一个参数的地址,也就是内存的地址(相当于指针).他们的区别是如果函数里面对传入的参数重新赋值,函数外的全局变量是否相应改变,用传值传入的参数是不会 ...

  5. Python的进阶:copy与deepcopy区别

    copy()与deepcopy()之间的区分必须要涉及到python对于数据的存储方式. 首先直接上结论: —–我们寻常意义的复制就是深复制,即将被复制对象完全再复制一遍作为独立的新个体单独存在.所以 ...

  6. Python的copy()与deepcopy()区别

    Python的copy()与deepcopy()分别对应浅拷贝和深拷贝. 它们的理论区别: deepcopy():深复制(也就是寻常意义上的复制),即将被复制对象完全再复制一遍作为独立的新个体单独存在 ...

  7. Python字典方法copy()和deepcopy()的区别

    from copy import deepcopy # import deepcopy模块 d = {} d['name'] = ['black', 'guts'] # d = {'name': [' ...

  8. python copy模块

    python copy模块 copy模块用于对象的拷贝操作 该模块只提供了两个主要的方法: copy.copy:浅复制 copy.deepcopy:深复制 直接赋值,深拷贝和浅拷贝的区别 直接赋值:简 ...

  9. copy模块中的copy与deepcopy的区别

    前言 每空闲下来,就觉得以前写的博客很low........也许现在也很low~~~~好吧就当升级版的low吧~~~~ 如果要了解copy与deepcopy的区别,就需要了解Python的存储机制:P ...

随机推荐

  1. TensorFlow从1到2(十三)图片风格迁移

    风格迁移 <从锅炉工到AI专家(8)>中我们介绍了一个"图片风格迁移"的例子.因为所引用的作品中使用了TensorFlow 1.x的代码,算法也相对复杂,所以文中没有仔 ...

  2. 201871010109-胡欢欢《面向对象程序设计(java)》第十六周学习总结

    项目 内容 这个作业属于哪个课程 https://www.cnblogs.com/nwnu-daizh/ 这个作业的要求在哪里 https://www.cnblogs.com/nwnu-daizh/p ...

  3. 【CentOS7】CentOS7各个版本镜像下载地址(转)

    链接:https://www.cnblogs.com/caidingyu/p/10679422.html # CentOS7.6 下载地址       # CentOS-7-x86_64-DVD-18 ...

  4. python之大作业

    一.题目要求 获得网页中A-Z所有名字并且爬取名字详情页中的信息,如姓名,性别,,说明等,并存放到csv中(网址:http://www.thinkbabynames.com/start/0/A) 现在 ...

  5. Rails + Webpacker + Puma + Nginx 部署

    准备 ssh 登录 首先 ssh 登录服务器,免密码登录可以参考 ssh 免密码登录服务器 创建部署用户 $ sudo adduser deploy 安装依赖 Ruby 这里使用 RVM 安装和管理 ...

  6. python做中学(九)定时器函数的用法

    程序中,经常用到这种,就是需要固定时间执行的,或者需要每隔一段时间执行的.这里经常用的就是Timer定时器.Thread 类有一个 Timer子类,该子类可用于控制指定函数在特定时间内执行一次. 可以 ...

  7. IT兄弟连 HTML5教程 HTML5的基本语法 如何选择开发工具

    如何选择开发工具 有许多可以编辑网页的软件,事实上你不需要用任何专门的软件来建立HTML页面,你所需要的只是一个文本编辑器(或字处理器),如Office Word.记事本.写字板等.制作页面初学者通常 ...

  8. glibc编译安装

    glibc是gnu发布的libc库,即c运行库.glibc是linux系统中最底层的api,几乎其它任何运行库都会依赖于glibc.glibc除了封装linux操作系统所提供的系统服务外,它本身也提供 ...

  9. python多进程multiprocessing Pool相关问题

    python多进程想必大部分人都用到过,可以充分利用多核CPU让代码效率更高效. 我们看看multiprocessing.pool.Pool.map的官方用法 map(func, iterable[, ...

  10. SQL Server内部如何管理对象的数据Page?

    一个表或Index使用的数据页空间是由IAM Page Chain来管理的.SQL Server 使用一个IAM(Index Allocation Map)Page来管理数据库文件中最多4GB的空间, ...