Python之探究类的复制和垃圾回收

 

Python之探究类的复制和垃圾回收

分类: python   48人阅读  评论(0)  收藏  举报

目录(?)[+]

一、引用计数和垃圾回收

先看一段代码:

[python]  view plain copy print ?
  1. In [43]: a = 34  
  2.   
  3. In [44]: b = a  
  4.   
  5. In [45]: del a  
  6.   
  7. In [46]: b  
  8. Out[46]: 34  
  9.   
  10. In [47]: a  
  11. ---------------------------------------------------------------------------  
  12. NameError                                 Traceback (most recent call last)  
  13. /home/kehr/<ipython-input-47-60b725f10c9cin <module>()  
  14. ----> 1 a  
  15.   
  16. NameError: name 'a' is not defined  

就以上这段代码,说说我的理解。

由于,a和b是指向同一块内存的引用,那么,修改a的值b的值一定会改变。

亮点在 “del a” 这一句,执行这句代码,销毁的是a这个引用变量呢,还是a指向的那块内存呢?或者是二者都被销毁了呢?

那就打印一下b和a

可以看见b和它指向的那块内存并没有消失,而b又是和a指向同一块内存。所以 del a 只是销毁了a这个引用变量

打印一下a,就会出现 NameError 的错误提示。

小结一下: del 只会销毁内存的引用

那么还有点问题,是不是由于数字和字符串这些是共享常量才会出现这种结果呢?我们再来测试一下一个全新的对象试一试

[python]  view plain copy print ?
  1. In [49]: a = [1,2,3]  
  2.   
  3. In [50]: b = a  
  4.   
  5. In [51]: del a  
  6.   
  7. In [52]: b  
  8. Out[52]: [123]  
  9.   
  10. In [53]: a  
  11. ---------------------------------------------------------------------------  
  12. NameError                                 Traceback (most recent call last)  
  13. /home/kehr/<ipython-input-53-60b725f10c9cin <module>()  
  14. ----> 1 a  
  15.   
  16. NameError: name 'a' is not defined  

可以看到,结果是一样的。那么我是不是可以下一个结论:del 语句只会销毁对象的引用变量,而对对象没有影响。

这里的对象指的是内存中的一块空间。

那么,如果 a = [“zhangsan”,"lisi"] 我们销毁了a,对象["zhangsan","lisi"]去哪里了呢?会不会内存泄露呢?

其实我们不必担心,python的垃圾回收机制,会帮我们解决这一问题。这里我们就需要了解一下对象的引用计数了

每一个对象被创建后,它的引用计数就会加一,当有其它变量再次引用该对象的时候,引用计数再次加一。如果删除这个对象的一个引用,它的引用计数就会减一。当一个对象的引用计数变为零的时候,就会被当做垃圾,被处理掉。

二、引用与复制

先来看这几条条语句:

[python]  view plain copy print ?
  1. In [2]: a = [1,2,3]  
  2.   
  3. In [3]: b = a  
  4.   
  5. In [4]: import copy  
  6.   
  7. In [5]: c = list(a)  
  8.   
  9. In [6]: d = copy.deepcopy(a)  
  10.   
  11. In [7]: b  
  12. Out[7]: [123]  
  13.   
  14. In [8]: c  
  15. Out[8]: [123]  
  16.   
  17. In [9]: d  
  18. Out[9]: [123]  

看起来 b,c,d 都成功的把a的值“复制”过来了,但是他们是不同的。不同在哪里呢?我们知道,复制,是把一个变量的值copy一份到另外一个变量中,两个变量相互独立,对其中一个变量值的修改并不影响另一个变量的值。以上这段代码的做法体现的不同之处就在这里。

下面这几段代码,先看看效果:

[python]  view plain copy print ?
  1. In [7]: a  
  2. Out[7]: [123]  
  3.   
  4. In [8]: b  
  5. Out[8]: [123]  
  6.   
  7. In [9]: c  
  8. Out[9]: [123]  
  9.   
  10. In [10]: d  
  11. Out[10]: [123]  
b = a, c = list(a), d = copy.deepcopy(a)


[python]  view plain copy print ?
  1. In [14]: a  
  2. Out[14]: [123]  
  3.   
  4. In [15]: a.append([45,34])  
  5.   
  6. In [16]: a  
  7. Out[16]: [123, [4534]]  
  8.   
  9. In [17]: b  
  10. Out[17]: [123, [4534]]  
  11.   
  12. In [18]: c  
  13. Out[18]: [123]  
  14.   
  15. In [19]: d  
  16. Out[19]: [123]  
可以看到a改变之后,只有b变了,c和d是不是真的完成了复制呢?


[python]  view plain copy print ?
  1. In [32]: a  
  2. Out[32]: [123, [4534]]  
  3.   
  4. In [33]: c = list(a)  
  5.   
  6. In [34]: d = copy.deepcopy(a)  
  7.   
  8. In [35]: b  
  9. Out[35]: [123, [4534]]  
  10.   
  11. In [36]: c  
  12. Out[36]: [123, [4534]]  
  13.   
  14. In [37]: a[3][0] = 'zhangsan'  
  15.   
  16. In [38]: a  
  17. Out[38]: [123, ['zhangsan'34]]  
  18.   
  19. In [39]: b  
  20. Out[39]: [123, ['zhangsan'34]]  
  21.   
  22. In [40]: c  
  23. Out[40]: [123, ['zhangsan'34]]  
  24.   
  25. In [41]: d  
  26. Out[41]: [123, [4534]]  
到这里,我们能看出,当a改变,b,c也随之改变了,d依旧没变,那是不是说明只有d是成功的完成了复制,b和c都没有复制成功呢?这只对了一半,下面我们来一一说明。

第一句:b = a

可能用惯了C和Java对与复制这个概念,认为这么做就完成了复制。但是在python中这么做是不对的。我在python的书上看到这句话的解释是:“b是对a的引用”

对此,我有两种理解:

1、有一块内存地址存放着对象 [1,2,3] ,变量a作为这块内存的引用,存储了它的地址,变量b作为a的引用存储了a的地址

2。有一块内存地址存放着对象 [1,2,3] ,变量a和b作为这块内存的引用,都存储了它的地址。

比较这两个,我更倾向于第二种理解。

如此,修改a的值b的值也会被修改。


第二句:c = list(a)

这一句实际上是完成了对a的复制的,但是复制的不够彻底,这种复制被称为“浅复制”。为什么呢?

这样看a的内容了。如果a中没有包含对象(a = [1,2,3]   c = list(a)  ),那么c的这种复制是成功的,c的内容和a是各自独立的。复制的时候又创建了一块新的内存,存放a指向的那块内存的内容。

但是,如果a中包含对象(a = [1,2,3,[45,34]], c = list(a)),那么c的这种复制只成功了一半。首先,还是会创建一块内存,存放a对象中的内容,可是a对象中的内嵌对象是不会被复制过来的,他会由a和c共享。也就是说,除了内嵌脆响之外,其他的元素都是相互独立的,只有内嵌对象是被共享的。修改内嵌对象的值c和a的值都会改变,修改其它非对象元素,c和a的值只会改变一个。


第三句:d  = copy.deepcopy(a)

这是为了解决第二句的漏洞而设计的。使用这一句才能够把a中的所有元素和对象完全复制。d和a是独立的,修改a中的元素和对象的值都不会影响d中的元素和对象的值。这种复制称为“深复制”


这三种复制,不能说哪一种更好,灵活的运用在需要他们的地方,才能体现出各自的价值和优越性。


初学python,本文内容只作为学习过程的一个总结和理解的记录。其中不乏有用词不当的地方。有些地方也是自己实验过后得出的总结,可能还不够全面。如果您觉得我的理解有错误和偏差,希望您能够在留言中指出来,我会继续去探究印证。谢谢啦!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值