最近有一個業務場景需要用Python自行實現一個簡單的LRU cache,不可避免的接觸到了弱參照這一概念,這裡記錄一下。
Python記憶體回收由垃圾回收器自動管理,當一個物件的參照計數歸0時,其記憶體就可能被回收掉,而參照計數器的數值其實就是代表有多少個強參照指向該物件,我們日常寫的Python程式碼如果沒有使用到weakref模組一般都只會涉及到強參照。
可以通過sys.getrefcount檢視物件的參照計數,如以下程式碼:
import sys
alist = [1, 2, 3] # alist參照計數=1
print(sys.getrefcount(alist)) # 包括getrefcount本身新增的強參照,輸出2
blist = alist
print(sys.getrefcount(alist)) # 新增blist強參照,輸出3
print(blist) # 輸出[1, 2, 3]
del blist
print(sys.getrefcount(alist)) # 刪除了blist,強參照-1, 輸出2
與強參照相對,弱參照並不會影響物件的參照計數,也就是說其不影響物件是否被回收的判定,如以下程式碼:
import sys
import weakref
class tlist(list): # list本身不支援弱參照,但其子類支援
pass
alist = tlist([1, 2, 3]) # alist參照計數=1
print(sys.getrefcount(alist)) # 輸出2
bref = weakref.ref(alist) # bref為對alist物件的弱參照
print(bref()) # 返回弱參照物件,輸出: [1, 2, 3]
print(sys.getrefcount(alist)) # 由於弱參照不影響參照計數,依然輸出2
del alist # 刪除alist,物件參照計數變為0
print(bref()) # 由於bref指向的物件已無任何強參照,返回None
如上程式碼所示弱參照不會影響物件的參照計數,亦即不會影響物件記憶體的回收,但是這裡碰到一個引人疑惑的點,就是Python中的基本資料型別對弱參照的支援分了三種情況。
基礎型別int、list、dict、tuple、str不支援弱參照,對其執行弱參照會報錯:
---------------------------------------------------------------------------
TypeError Traceback (most recent call last)
<ipython-input-3-9daeb515714d> in <module>
----> 1 weakref.ref(alist)
TypeError: cannot create weak reference to 'list' object
可以通過__weakrefoffset__檢視型別是否支援弱參照,該變數表示弱參照指標相對物件起始地址的偏移量,>0表示支援弱參照:
In [1]: int.__weakrefoffset__
Out[1]: 0
In [2]: str.__weakrefoffset__
Out[2]: 0
In [3]: tuple.__weakrefoffset__
Out[3]: 0
In [4]: list.__weakrefoffset__
Out[4]: 0
In [5]: dict.__weakrefoffset__
Out[5]: 0
In [6]: set.__weakrefoffset__
Out[6]: 192
官方檔案中介紹:
Several built-in types such as list and dict do not directly support weak references but can add support through subclassing:
CPython implementation detail: Other built-in types such as tuple and int do not support weak references even when subclassed.
總結基礎型別對弱參照的支援分為以下三種情況(for python3.8):
這又是出於什麼考慮?通過一番探究得出以下可能原因:
轉載請註明出處,原文地址:https://www.cnblogs.com/AcAc-t/p/python_weakref_study.html
https://docs.python.org/3.8/library/weakref.html
https://www.cnblogs.com/marsggbo/p/14831456.html
https://www.cnblogs.com/AcAc-t/p/python_weakref_study.html
https://stackoverflow.com/questions/52011430/python-which-types-support-weak-references