python 引用,拷贝,对象回收,弱引用

引用

python中,在对对象赋值,参数传递,函数返回等等, 都是引用传递的. 直接copy个例子来【1】:

 a = [1, 2, 3]
 b = a
 b.append(5)
 print a, b 

  输出结果为:

[1, 2, 3, 5] [1, 2, 3, 5]

上面的结果有助于理解引用的实际情况。 具体查看一个对象的引用数,可以使用sys.getrefcount(ojb)获取,但这个函数有点邪恶,有时似乎并不给出正确的结果,正常来说获取的值都比你想要的大,一般是大1,因为给这个函数传参数也算一个引用。但有时会大得离谱,来例子:

import sys
a = "a"
sys.getrefcount(a)


在我的机器上,输出结果尽然为14,网络遛了一圈,有人说是python内部对“a”这个对象进行了应用。好吧!就这样理解把,有高见的可以留言告我一下!

拷贝【1】

拷贝主要有两种拷贝,分别以copy模块中的两个函数copy和deepcopy为代表。其中,前者复制对象本身,但对于对象中得元素,还是会使用的原本引用,copy个例子来:

list_of_lists = [ ['a'], [1, 2], ['z', 23] ]
copy_lol = copy.copy(lists_of_lists)
copy_lol[1].append('boo')
print list_of_lists, copy_lol

输出结果为:
[['a'], [1, 2, 'boo'], ['z', 23]] [['a'], [1, 2, 'boo'], ['z', 23]]

考到第二个元素的情况了 把!用的还是引用。要想全部对对象本省进行拷贝,就得使用deepcopy了。

对象回收

Python使用了垃圾回收器来自动销毁那些不再使用的对象。当对某个对象的引用计数为0时, Python能够安全地销毁这个对象。表面上看来,在使用C或者C++时经常会碰到的内存泄露问题似乎也就解决了,但实际的情况是,请你小心!再copy个例子来【2】:

class LeakTest(object):
   def __init__(self):
     print 'Object with id %d born here.' % id(self)
   def __del__(self):
     print 'Object with id %d dead here.' % id(self)

def foo():
   A = LeakTest()
   B = LeakTest()
   A.b = B
   B.a = A
if __name__ = ="__main__": 
  foo()

运行结果为:
Object with id 10462448 born here.
Object with id 10462832 born here.

在构造一个类时,__init__会被自动调用;在进行对象回收时,__del__会被调用。很清楚的看到对象只是被创建了,而没有被回收,原因很简单,A和B的由于互相引用,他们的引用次数是不可能为0的,自然被回收也是不可能的了。这是,就应该考虑弱引用了。

弱引用

这是相对上面“引用”的一个概念,主要不同体现在对象回收时,上面我只提到当引用数为0,对象就会自动回收。其实还有另外一种情况,当自由只有对对象的弱引用时,对象也是会被回收。直接上代码,对上例做出一些修改:

import weakref
class LeakTest(object):
   def __init__(self):
     print 'Object with id %d born here.' % id(self)
   def __del__(self):
     print 'Object with id %d dead here.' % id(self)

def foo():
   A = LeakTest()
   B = LeakTest()
   A.b = weakref.proxy(B)
   B.a = weakref.proxy(A)
if __name__ = ="__main__": 
  foo()

运行结果为:
Object with id 28637456 born here.
Object with id 29402736 born here.
Object with id 28637456 dead here.
Object with id 29402736 dead here.
 

OK了,对象被正常回收了!最后简单解说wekref中得几个函数【3】:

1.创建弱引用:

你可以通过调用weakref模块的ref(obj[,callback])来创建一个弱引用,obj是你想弱引用的对象,callback是一个可选的函数,当因没有引用导致Python要销毁这个对象时调用。回调函数callback要求单个参数(弱引用的对象)。
一旦你有了一个对象的弱引用,你就能通过调用弱引用来获取被弱引用的对象。下面的例子创建了一个对socket对象的弱引用:
>>> from socket import *
>>> import weakref
>>> s=socket(AF_INET,SOCK_STREAM)
>>> ref=weakref.ref(s)
>>> s
<socket._socketobject instance at 007B4A94>
>>> ref
<weakref at 0x81195c; to 'instance' at 0x7b4a94>
>>> ref()    #调用它来访问被引用的对象
<socket.socketobject instance at 007B4A94>

2. 创建代理对象

代理对象是弱引用对象,它们的行为就像它们所引用的对象,这就便于你不必首先调用弱引用来访问背后的对象。通过weakref模块的proxy(obj[,callback])函数来创建代理对象。使用代理对象就如同使用对象本身一样:
>>> from socket import*
>>> import weakref
>>> s=socket(AF_INET,SOCK_STREAM)
>>> ref=weakref.proxy(s)
>>> s
<socket._socketobject instance at 007E4874>
>>> ref
<socket._socketobject instance at 007E4874>
>>> ref.close() #对象的方法同样工作


callback参数的目的和ref函数相同。在Python删除了一个引用的对象之后,使用代理将会导致一个weakref.ReferenceError错误:
>>> del s
>>> ref
Traceback (most recent call last):
  File "<stdin>", line 1, in ?

3. getweakrefcount(obj)和getweakrefs(obj)分别返回弱引用数和关于所给对象的引用列表

参考文献:

【1】 http://blog.sina.com.cn/s/blog_5357c0af0100n2q5.html

【2】http://linhs.blog.51cto.com/370259/142846/

【3】http://longmans1985.blog.163.com/blog/static/70605475200991613556128/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章