Python深拷贝和浅拷贝
1- Python引用计数[1]
1.1 引用计数机制
引用计数是计算机编程语言中的一种内存管理技术,是指将资源(可以是对象、内存或磁盘空间等等)的被引用次数保存起来,当被引用次数变为零时就将其释放的过程。使用引用计数技术可以实现自动资源管理的目的。同时引用计数还可以指使用引用计数技术回收未使用资源的垃圾回收算法。
当创建一个对象的实例并在堆上申请内存时,对象的引用计数就为1,在其他对象中需要持有这个对象时,就需要把该对象的引用计数加1,需要释放一个对象时,就将该对象的引用计数减1,直至对象的引用计数为0,对象的内存会被立刻释放。
1.2 垃圾回收
当对象的引用计数为0,对象的内存会被立刻释放,称为垃圾回收。
1.3 引用计数增加情况
(1). 对象被创建:x=4
(2). 另外的别人被创建:y=x
(3). 被作为参数传递给函数:foo(x)
(4). 作为容器对象的一个元素:a=[1,x,'33']
1.4 引用计数减少情况
(1). 一个本地引用离开了它的作用域。比如上面的foo(x)函数结束时,x指向的对象引用减1。
(2). 对象的别名被显式的销毁:del x ;或者del y
(3). 对象的一个别名被赋值给其他对象:x=789
(4). 对象从一个窗口对象中移除:myList.remove(x)
(5). 窗口对象本身被销毁:del myList,或者窗口对象本身离开了作用域。
2- 深浅拷贝[2,3]
2.1 赋值
其实python中的赋值其实是使引用计数+1,例如:
foo1 = 1.0
foo2 = foo1
foo1 is foo2 #True
id(foo1) = 18719720
id(foo2) = 18719720
但是如果是这样:
foo1=1.0
foo2=1.0
foo1 is foo2 #False
id(foo1) = 18719888
id(foo2) = 18719840
这时你会发现,这其实是创建了两个不同的对象,用内建函数id()可以发现,二者的身份不同。
其实python还有一个特例,例如:
a = 1
b = 1
id(a) = 14332248
id(b) = 14332248
原因是python认为这些小整型是会经常用到的,所以python会缓存一部分小整型。
2.2 深拷贝 & 浅拷贝
序列类型的可以通过三种方式实现浅拷贝,浅拷贝也是默认的拷贝类型:(1)完全切片操作;(2)利用工厂函数,比如list()等;(3)使用copy模块中的copy()函数。
在《Python核心编程》一书中说道,“对一个对象进行浅拷贝其实是新创建了一个类型跟原对象一样,其内容是原来对象元素的引用,换句话说,这个拷贝的对象本身是新的,但是它的内容不是”。
import copy
a = [1, 2, 3, 4, ['a', 'b', 'c']]
b = a
c = copy.copy(a) id(a) #139879301469392
id(b) #139879301469392
id(c) #139879298646816, 可以看出所谓的“拷贝对象本身是新的“ [id(x) for x in a] #[14332248, 14332224, 14332200, 14332176, 139879298781912]
[id(x) for x in b] #[14332248, 14332224, 14332200, 14332176, 139879298781912]
[id(x) for x in c] #[14332248, 14332224, 14332200, 14332176, 139879298781912], 即”内容是旧的“
最后,深拷贝和浅拷贝的区别^_^
import copy
a = [1, 2, 3, 4, ['a', 'b', 'c']]
c = copy.copy(a)
d = copy.deepcopy(a) id(a) #139879301469392
id(c) #
id(d) # [id(x) for x in a] #[14332248, 14332224, 14332200, 14332176, 139879298781912]
[id(x) for x in c] #[14332248, 14332224, 14332200, 14332176, 139879298781912]
[id(x) for x in d] #[14332248, 14332224, 14332200, 14332176, 139879302072512] ##################################
a.append(5)
a[4].append('hello') a #[1, 2, 3, 4, ['a', 'b', 'c', 'hello'], 5]
c #[1, 2, 3, 4, ['a', 'b', 'c', 'hello']]
d #[1, 2, 3, 4, ['a', 'b', 'c']] [id(x) for x in a] #[14332248, 14332224, 14332200, 14332176, 139879298781912, 14332152]
[id(x) for x in c] #[14332248, 14332224, 14332200, 14332176, 139879298781912]
[id(x) for x in d] #[14332248, 14332224, 14332200, 14332176, 139879302072512] #################################
a[1] = 0
c[2] = 0
d[3] = 0 a #[1, 0, 3, 4, ['a', 'b', 'c', 'hello'], 5]
c #[1, 2, 0, 4, ['a', 'b', 'c', 'hello']]
d #[1, 2, 3, 0, ['a', 'b', 'c']] [id(x) for x in a] #[14332248, 14332272, 14332200, 14332176, 139879298781912, 14332152] a[1]关联到新对象 [id(x) for x in c] #[14332248, 14332224, 14332272, 14332176, 139879298781912] c[2]关联到新对象 [id(x) for x in d] #[14332248, 14332224, 14332200, 14332272, 139879302072512] d[3]关联到新对象
################################
#
del a[0]
a #[ 0, 3, 4, ['a', 'b', 'c', 'hello'], 5]
c #[1, 2, 0, 4, ['a', 'b', 'c', 'hello']]
d #[1, 2, 3, 0, ['a', 'b', 'c']] del c[0]
a #[ 0, 3, 4, ['a', 'b', 'c', 'hello'], 5]
c #[ 2, 0, 4, ['a', 'b', 'c', 'hello']]
d #[1, 2, 3, 0, ['a', 'b', 'c']] del d[0]
a #[ 0, 3, 4, ['a', 'b', 'c', 'hello'], 5]
c #[ 2, 0, 4, ['a', 'b', 'c', 'hello']]
d #[ 2, 3, 0, ['a', 'b', 'c']] #
del a[3][0]
a #[ 0, 3, 4, [ 'b', 'c', 'hello'], 5]
c #[ 2, 0, 4, [ 'b', 'c', 'hello']]
d #[ 2, 3, 0, ['a', 'b', 'c']]
简单点说
1. copy.copy 浅拷贝 -拷贝一个对象,但是对象的属性还是引用原来的。拷贝了一个不可变的对象的引用, 修改你得到的变量只会让该变量的引用指向一个新的对象(如a或c中数值元素改变不会影响另一个)
可以这样记忆,浅拷贝的各个元素整体上改变是没有影响的,但仅元素部分修改是互相牵制的
a = [1, 2, ['a', 'b'], ['c', 'd']]
b = copy.copy(a) #整体
a[0] = 0
a #[0, 2, ['a', 'b'], ['c', 'd']]
b #[1, 2, ['a', 'b'], ['c', 'd']] del a[3]
a #[0, 2, ['a', 'b']]
a #[1, 2, ['a', 'b'], ['c', 'd']] #局部
a[2].append('haha')
a #[0, 2, ['a', 'b', 'haha']]
a #[1, 2, ['a', 'b', 'haha'], ['c', 'd']]
2. copy.deepcopy 深拷贝 -拷贝一个对象,把对象里面的属性也做了拷贝,deepcopy之后完全是另一个对象了,实现完全独立
#打印['a','b','c']地址
[id(x) for x in a[3]] #[1398793470232, 139879343471752, 139879314380720]
[id(x) for x in c[3]] #[1398793470232, 139879343471752, 139879314380720]
[id(x) for x in d[3]] #[1398793470192, 139879343470232, 139879343471752]
[3] 从Python中copy与deepcopy的区别看Python引用
Python深拷贝和浅拷贝的更多相关文章
- python 深拷贝与浅拷贝
浅拷贝的方式有: lst=[1,2,3] (1)直接赋值: lst_cp = lst (2)for循环遍历生成:lst_cp= [i for i in lst] (3)copy模块下,copy.cop ...
- 【python测试开发栈】—理解python深拷贝与浅拷贝的区别
内存的浅拷贝和深拷贝是面试时经常被问到的问题,如果不能理解其本质原理,有可能会答非所问,给面试官留下不好的印象.另外,理解浅拷贝和深拷贝的原理,还可以帮助我们理解Python内存机制.这篇文章将会通过 ...
- Python深拷贝与浅拷贝区别
可变类型 如list.dict等类型,改变容器内的值,容器地址不变. 不可变类型 如元组.字符串,原则上不可改变值.如果要改变对象的值,是将对象指向的地址改变了 浅拷贝 对于可变对象来说,开辟新的内存 ...
- Python 深拷贝和浅拷贝的区别
python的复制,深拷贝和浅拷贝的区别 在python中,对象赋值实际上是对象的引用.当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用 ...
- python深拷贝和浅拷贝的区别
首先深拷贝和浅拷贝都是对象的拷贝,都会生成一个看起来相同的对象,他们本质的区别是拷贝出来的对象的地址是否和原对象一样,也就是地址的复制还是值的复制的区别. 什么是可变对象,什么是不可变对象: 可变对象 ...
- Python——深拷贝和浅拷贝
深拷贝.浅拷贝 1. 浅拷贝 浅拷贝是对于一个对象的顶层拷贝 import copy a = [[1, 2], 3] b = copy.copy(a) print(id(a)) print(id(b) ...
- PYTHON 深拷贝,浅拷贝
声明:本篇笔记,模仿与其它博客中的内容 浅拷贝 浅拷贝,在内存中只额外创建第一层数据 import copy n1 = {"k1": "wu", "k ...
- Python 深拷贝和浅拷贝
Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 对象赋值 直接看一段代码: will= ...
- Python深拷贝和浅拷贝!
在python中,对象赋值实际上是对象的引用.当创建一个对象,然后把它赋给另一个变量的时候,python并没有拷贝这个对象,而只是拷贝了这个对象的引用 一般有三种方法, alist=[1,2,3,[& ...
随机推荐
- 代码片段 - Golang 创建 .tar.gz 压缩包
Golang创建 .tar.gz 压缩包 tar 包实现了文件的打包功能,可以将多个文件或目录存储到单一的 .tar 文件中,tar 本身不具有压缩功能,只能打包文件或目录: import " ...
- LeetCode9 Palindrome Number
题意: Determine whether an integer is a palindrome. Do this without extra space. (Easy) 分析: 自己考虑的方法是利 ...
- 快递鸟API接口调用代码示例(免费不限量)
import java.io.BufferedReader; import java.io.IOException; import java.io.InputStreamReader; import ...
- H - The Falling Leaves
Description Each year, fall in the North Central region is accompanied by the brilliant colors of th ...
- 6. Android框架和工具之 JSON解析
Android进阶笔记17:3种JSON解析工具(org.json.fastjson.gson)
- leetcode 题解:Binary Tree Inorder Traversal (二叉树的中序遍历)
题目: Given a binary tree, return the inorder traversal of its nodes' values. For example:Given binary ...
- mysql mysql_error mysqli_connect_error 乱码
<html> <head> <meta charset="utf-8"> <title></title> </he ...
- mysql优化方法
1.选取最适用的字段属性 MySQL可以很好的支持大数据量的存取,但是一般说来,数据库中的表越小,在它上面执行的查询也就会越快.因此,在创建表的时候,为了获得更好的性能,我们可以将表中字段的宽度设得尽 ...
- Java为什么只能单继承?
就是因为C++里多重继承功能强大但是容易出错,Java才给取消掉了.如果,A和B都继承于C,再写个D继承A和B.那么C里面有个方法,A和B继承过去后都进行了覆盖,那么D到底是该继承A里面的版本呢还是B ...
- 管理后台-第一部分:Creating custom sections in Umbraco 7 - Part 1(翻译文档)
在Umbraco上每个部分都可以被称为一个应用程序,所以这些部分和应用程序基本上是一样的.我们首先要做的事情是需要创建应用程序.在这个例子中,我不会去摆弄xml文件或是数据库——我将使用类来创建我的内 ...