在 Python 的對象模型中,變量的“賦值”本質(zhì)上是引用綁定(binding)。只要存在至少一個(gè)強(qiáng)引用指向某個(gè)對象,該對象就不會被垃圾回收。然而,有些場景中我們需要“觀察對象是否還存在”,又不希望阻止其被回收,這時(shí)就需要弱引用(Weak Reference)。__weakref__ 正是弱引用機(jī)制在對象內(nèi)部的核心載體。
一、__weakref__ 是什么?
__weakref__ 是 Python 對象中的一個(gè)內(nèi)置屬性,用于存儲該對象被弱引用(weakref 模塊)追蹤的信息。它通常由 Python 自動管理,用戶無需直接操作,但理解它有助于掌握弱引用的底層原理。
核心功能:
? 存儲指向該對象的所有弱引用(weakref.ref、weakref.proxy 等)。
? 當(dāng)對象支持弱引用時(shí),Python 會自動為其實(shí)例生成此屬性。
? 若類使用 __slots__ 禁止了動態(tài)屬性,必須顯式聲明 __weakref__ 才能支持弱引用。
語法:
object.__weakref__示例:
print(d.__weakref__) # 輸出:
在 CPython 中,每個(gè)對象都有一個(gè)引用計(jì)數(shù)(Reference Count),當(dāng)引用計(jì)數(shù)歸零時(shí),對象會被垃圾回收(GC),這種方式又稱為“強(qiáng)引用”。
del b # 引用計(jì)數(shù)為 0,對象被銷毀弱引用不會增加對象的引用計(jì)數(shù),因此不會阻止對象被回收。
print(w()) # 輸出:None(對象已被回收,弱引用失效)二、weakref 模塊的使用
Python 提供了 weakref 標(biāo)準(zhǔn)庫來管理弱引用。
weakref.ref(obj):創(chuàng)建弱引用對象。
weakref.proxy(obj):創(chuàng)建自動解引用的代理。
weakref.WeakKeyDictionary:鍵為弱引用的字典。
weakref.WeakValueDictionary:值為弱引用的字典。
當(dāng)我們通過 weakref.ref(obj) 創(chuàng)建弱引用時(shí),Python 會將弱引用對象登記在目標(biāo)對象的 __weakref__ 屬性中。因此,__weakref__ 可以理解為:對象內(nèi)部用于記錄所有弱引用它的“登記表”。
三、__weakref__ 與 __slots__ 的關(guān)系
如果類定義了 __slots__,默認(rèn)情況下不會自動創(chuàng)建 __weakref__ 屬性,從而導(dǎo)致實(shí)例不支持弱引用。
錯(cuò)誤示例:
# 輸出:cannot create weak reference to 'A' object正確示例:
print(w) # 正常輸出若類定義了 __slots__ 且需支持弱引用,必須將 "__weakref__" 顯式包含在 __slots__ 列表中。
四、弱引用的典型應(yīng)用場景
(1)緩存與對象池
適用于圖像、模型、數(shù)據(jù)庫連接等資源,希望緩存對象但又不阻止其回收。
print(list(_cache.keys())) # [] 緩存自動清除(2)打破循環(huán)引用
弱引用常用于解決對象間的循環(huán)依賴問題。
問題代碼(循環(huán)引用):
child.parent = root # 互相強(qiáng)引用,形成循環(huán)改進(jìn)代碼(使用弱引用):
root.children.append(child) # root 強(qiáng)引用 child (單向)(3)GUI、事件系統(tǒng)與觀察者模式
在 GUI 框架或事件系統(tǒng)中,常用弱引用來注冊回調(diào)函數(shù),避免因回調(diào)持有對象引用而導(dǎo)致控件無法釋放。
五、生命周期與內(nèi)存管理
弱引用的價(jià)值在于:允許觀察對象存活狀態(tài),而不擁有對象。
生命周期主要分為三個(gè)階段。
(1)創(chuàng)建階段
首次對對象創(chuàng)建弱引用時(shí):
? Python 為對象建立內(nèi)部弱引用鏈表(__weakref__)
? 弱引用對象加入鏈表
? 不增加引用計(jì)數(shù)
w = weakref.ref(obj) # obj 的引用計(jì)數(shù)不變(2)存活階段(對象仍存在)
? 調(diào)用 w() 返回原對象
? 對象正常使用,不受弱引用影響
? 弱引用不會阻止對象被垃圾回收
示例:
t.do_something()(3)銷毀階段(對象被回收)
當(dāng)對象被 GC 回收時(shí):
? 所有弱引用失效
? 回調(diào)(如果有)被調(diào)用
? w() 永遠(yuǎn)返回 None
print(w()) # None如果使用 proxy:
p = weakref.proxy(A())對象消失后:
# ReferenceError: weakly-referenced object no longer existsproxy 的安全性不如 ref,需要注意。
六、常見誤區(qū)與注意事項(xiàng)
(1)并非所有類型都支持弱引用
內(nèi)置類型(int, str, tuple, list 等)通常不支持。
print(hasattr(x, "__weakref__")) # False,內(nèi)置類型 int 不支持弱引用僅用戶自定義類或特定擴(kuò)展類型支持弱引用。
(2)弱引用不會延長對象壽命
弱引用只觀察對象,不影響引用計(jì)數(shù)。
(3)使用弱引用要檢查有效性
若對象被銷毀后仍使用弱引用結(jié)果,會得到 None,需始終檢查返回值有效性。
小結(jié)
__weakref__ 是 Python 對象系統(tǒng)中一個(gè)低調(diào)卻至關(guān)重要的機(jī)制。它使得我們可以在不干擾對象生命周期的前提下,安全地追蹤、緩存或引用對象——這對于內(nèi)存優(yōu)化、循環(huán)引用處理、事件系統(tǒng)都有深遠(yuǎn)意義。
![]()
“點(diǎn)贊有美意,贊賞是鼓勵(lì)”
特別聲明:以上內(nèi)容(如有圖片或視頻亦包括在內(nèi))為自媒體平臺“網(wǎng)易號”用戶上傳并發(fā)布,本平臺僅提供信息存儲服務(wù)。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.