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]

[1] Python是如何进行内存管理的?

[2] Python的赋值、浅拷贝和深拷贝

[3] 从Python中copy与deepcopy的区别看Python引用

Python深拷贝和浅拷贝的更多相关文章

  1. python 深拷贝与浅拷贝

    浅拷贝的方式有: lst=[1,2,3] (1)直接赋值: lst_cp = lst (2)for循环遍历生成:lst_cp= [i for i in lst] (3)copy模块下,copy.cop ...

  2. PYTHON 深拷贝,浅拷贝

    声明:本篇笔记,模仿与其它博客中的内容 浅拷贝 浅拷贝,在内存中只额外创建第一层数据 import copy n1 = {"k1": "wu", "k ...

  3. Python 深拷贝和浅拷贝

    Python中,对象的赋值,拷贝(深/浅拷贝)之间是有差异的,如果使用的时候不注意,就可能产生意外的结果. 下面本文就通过简单的例子介绍一下这些概念之间的差别. 对象赋值 直接看一段代码: will= ...

  4. python 深拷贝和浅拷贝浅析

    简单点说 1. copy.copy 浅拷贝 只拷贝父对象,不会拷贝对象的内部的子对象.id会变化2. copy.deepcopy 深拷贝 拷贝对象及其子对象.id会变化 >>> im ...

  5. python 中 深拷贝和浅拷贝的理解

    在总结 python 对象和引用的时候,想到其实 对于python的深拷贝和浅拷贝也可以很好对其的进行理解. 在python中,对象的赋值的其实就是对象的引用.也就是说,当创建一个对象,然后赋给另外一 ...

  6. 理解python可变类型vs不可变类型,深拷贝vs浅拷贝

    核心提示: 可变类型 Vs 不可变类型 可变类型(mutable):列表,字典 不可变类型(unmutable):数字,字符串,元组 这里的可变不可变,是指内存中的那块内容(value)是否可以被改变 ...

  7. python中的深拷贝与浅拷贝

    深拷贝和浅拷贝 浅拷贝的时候,修改原来的对象,浅拷贝的对象不会发生改变. 1.对象的赋值 对象的赋值实际上是对象之间的引用:当创建一个对象,然后将这个对象赋值给另外一个变量的时候,python并没有拷 ...

  8. Python 引用、浅拷贝、深拷贝解析

    引用 Python是动态数据类型的语言,故在对变量进行赋值时是不用制定变量类型的. 或者说,你可以把变量赋值的过程,当作是贴一个标签,去引用该数据. 看下面的例子: In [54]: a=4 In [ ...

  9. Python赋值语句与深拷贝、浅拷贝的区别

    参考:http://stackoverflow.com/questions/17246693/what-exactly-is-the-difference-between-shallow-copy-d ...

随机推荐

  1. javascript设计模式:策略模式

    前言 策略模式有效利用组合.委托.多态等技术和思想,可以有效避免多重条件选择语句. 策略模式对开放-封闭原则提供了很好的支持,将算法封装在strategy中,使得他们易于切换.理解.扩展. 策略模式中 ...

  2. Linux上mongodb开机自启动

    1.下载MongoDB 2.安装MongoDB(安装到/usr/local下) .tgz mongodb cd mongodb mkdir db mkdir logs cd bin vi mongod ...

  3. Django框架初入

    一.Django 特性 数据库功能强大(利用python的类继承,几行代码就可以实现一个动态的数据库操作接口(API)) 强大的后台功能 优雅的网址(正则匹配网址,传递到对应函数) 模板与缓存系统 二 ...

  4. Git查看、删除、重命名远程分支和tag(转)

    转:http://zengrong.net/post/1746.htm 这篇文章记录我在使用git的过程中碰到远程分支和tag的相关内容,提纲: 查看远程分支 删除远程分支和tag 删除不存在对应远程 ...

  5. 用JSON.parse和eval出现的问题

    json格式非常受欢迎,而解析json的方式通常用JSON.parse()但是eval()方法也可以解析,这两者之间有什么区别呢? JSON.parse()之可以解析json格式的数据,并且会对要解析 ...

  6. javascript void运算符

    参考链接:http://www.cnblogs.com/ziyunfei/archive/2012/09/23/2698607.html语法: void expr 作用:计算表达式expr,并返回un ...

  7. [CareerCup] 4.1 Balanced Binary Tree 平衡二叉树

    4.1 Implement a function to check if a binary tree is balanced. For the purposes of this question, a ...

  8. UESTC 1817 Complete Building the Houses

    Complete Building the Houses Time Limit: 2000MS Memory Limit: 65535KB 64bit IO Format: %lld & %l ...

  9. adb 卸载APP命令和杀死APP命令

    使用adb 卸载APP命令 在cmd命令行下,直接 输入 adb uninstall 包名 比如 adb uninstall com.ghstudio.BootStartDemo 杀死APP命令 先用 ...

  10. win7下无法安装QTP-少了Microsoft Visual c++2005 sp1运行时组件

    问题是:当我点击QTP的setup.exe进行QTP安装时,出现提示[少了Microsoft Visual c++2005 sp1运行时组件,安装时会提示命令行选项语法错误,键入“命令/?”可获取帮肋 ...