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