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,[& ...
随机推荐
- /proc/sys/vm/ 内存参数
linux下proc里关于磁盘性能的参数 http://blog.csdn.net/eroswang/article/details/6126646 我们在磁盘写操作持续繁忙的服务器上曾经碰到一个特 ...
- cocos2d-x在android下的编译
$(call import-add-path,E:/cocos2d-2.0-x-2.0.3) include $(BUILD_SHARED_LIBRARY) http://www.cnblogs.co ...
- 终端I/O之终端窗口的大小
大多数UNIX系统都提供了一种功能,可以对当前终端窗口的大小进行跟踪,在窗口大小发生变化时,使内核通知前台进程组.内核为每个终端和伪终端保存一个winsize结构: Struct winsize { ...
- 数据剪切命令cut和数据粘贴命令pastte
在Windows中,经常从一个文件将一段文本移动到另一个文件中.在Linux中执行这个任务的是cut和paste命令. 一.数据剪切命令cut 命令格式: cut [option] [file] 常用 ...
- (转)ASP.NET Identity登录原理 - Claims-based认证和OWIN
在Membership系列的最后一篇引入了ASP.NET Identity,看到大家对它还是挺感兴趣的,于是来一篇详解登录原理的文章.本文会涉及到Claims-based(基于声明)的认证,我们会详 ...
- WPF 之 WPF应用程序事件
当新建一个wpf应用程序,会自动生成一个App.xaml和MainWindow.xaml文件. 其中 App.xam 用来设置Application,应用程序的起始文件和资源及应用程序的一些属性和事件 ...
- C# 之 user32函数库
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.R ...
- jQuery实现轮播图效果
通过改变背景色来达到效果,有下角标和左右箭头,都已经实现. html部分: <!DOCTYPE html> <html> <head> <meta chars ...
- epoll实现linux进程通信
server.c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <s ...
- Linux_netstat 详解
简介 Netstat 命令用于显示各种网络相关信息,如网络连接,路由表,接口状态 (Interface Statistics),masquerade 连接,多播成员 (Multicast Member ...