淺析Python中的弱引用與基礎類型支持情況
背景
最近有一個業(yè)務場景需要用Python自行實現(xiàn)一個簡單的LRU cache,不可避免的接觸到了弱引用這一概念,這里記錄一下。
強引用
Python內(nèi)存回收由垃圾回收器自動管理,當一個對象的引用計數(shù)歸0時,其內(nèi)存就可能被回收掉,而引用計數(shù)器的數(shù)值其實就是代表有多少個強引用指向該對象,我們?nèi)粘懙腜ython代碼如果沒有使用到weakref模塊一般都只會涉及到強引用。
可以通過sys.getrefcount查看對象的引用計數(shù),如以下代碼:
import sys alist = [1, 2, 3] # alist引用計數(shù)=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
弱引用
與強引用相對,弱引用并不會影響對象的引用計數(shù),也就是說其不影響對象是否被回收的判定,如以下代碼:
import sys
import weakref
class tlist(list): # list本身不支持弱引用,但其子類支持
pass
alist = tlist([1, 2, 3]) # alist引用計數(shù)=1
print(sys.getrefcount(alist)) # 輸出2
bref = weakref.ref(alist) # bref為對alist對象的弱引用
print(bref()) # 返回弱引用對象,輸出: [1, 2, 3]
print(sys.getrefcount(alist)) # 由于弱引用不影響引用計數(shù),依然輸出2
del alist # 刪除alist,對象引用計數(shù)變?yōu)?
print(bref()) # 由于bref指向的對象已無任何強引用,返回None如上代碼所示弱引用不會影響對象的引用計數(shù),亦即不會影響對象內(nèi)存的回收,但是這里碰到一個引人疑惑的點,就是Python中的基本數(shù)據(jù)類型對弱引用的支持分了三種情況。
基礎類型對于弱引用支持情況
基礎類型int、list、dict、tuple、str不支持弱引用,對其執(zhí)行弱引用會報錯:
---------------------------------------------------------------------------
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.
總結(jié)基礎類型對弱引用的支持分為以下三種情況(for python3.8):
- 對于list、dict、str本身不支持弱引用,但可以通過創(chuàng)建子類的方式對其進行弱引用
- 對于int、tuple本身及其子類均不支持弱引用
- set直接支持弱引用
這又是出于什么考慮?通過一番探究得出以下可能原因:
- 絕大部分場景下,基礎類型使用并不涉及到弱引用,所以基礎類型不支持弱引用可以有效避免相應的overhead。
- 弱引用添加于Python2.1,所以對于之后添加的類型(包括object、type、set等)默認都是支持弱引用的,除非有明確的理由不這么做。
- 對于list、dict、int、str、tuple這些2.1之前的基礎類型為了兼容性考慮均默認不支持弱引用,而set添加與2.3,因此其直接支持弱引用。
- int、str、tuple這些不可變對象,在CPython解釋器中會有特殊的處理邏輯:
4.1 如[-5, 256]范圍的小整數(shù)池一開始就被創(chuàng)建好了,在程序的整個生命周期無論是否被實際引用都不會被回收。
4.2 又如對于同一個compilation unit的tuple對象,如果取值相同,編譯器會將獨立的多個相同的tuple對象處理為指向同一個對象的多個強引用。
在這些情況下使用弱引用并沒有什么明顯的好處,反而額外引入了overhead,綜合考慮直接對其不支持弱引用。 - 出于CPython的具體實現(xiàn)細節(jié),對于int、tuple的子類也不支持弱引用。
到此這篇關(guān)于淺析Python中的弱引用與基礎類型支持情況的文章就介紹到這了,更多相關(guān)Python弱引用內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Python如何根據(jù)關(guān)鍵字逐行提取文本內(nèi)容問題
這篇文章主要介紹了Python如何根據(jù)關(guān)鍵字逐行提取文本內(nèi)容問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2023-08-08
python Tkinter實時顯示數(shù)據(jù)功能實現(xiàn)
這篇文章主要介紹了python Tkinter實時顯示數(shù)據(jù)功能實現(xiàn),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下2023-07-07
在Python 2.7即將停止支持時,我們?yōu)槟銕砹艘环輕ython 3.x遷移指南
這篇文章主要介紹了在Python 2.7即將停止支持時我們?yōu)槟銣蕚淞艘环輕ython 3.x遷移指南的相關(guān)資料,需要的朋友可以參考下2018-01-01
從0開始的Python學習014面向?qū)ο缶幊蹋ㄍ扑])
這篇文章主要介紹了Python面向?qū)ο缶幊蹋闹型ㄟ^示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2019-04-04
詳解從Django Rest Framework響應中刪除空字段
這篇文章主要介紹了詳解從Django Rest Framework響應中刪除空字段,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2019-01-01

