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/

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