日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 综合教程 >内容正文

综合教程

weakref:对象的弱引用

發(fā)布時間:2023/10/11 综合教程 99 老码农
生活随笔 收集整理的這篇文章主要介紹了 weakref:对象的弱引用 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

介紹

weakref支持對象的弱引用,正常的引用會增加對象的引用計數(shù),并避免它被垃圾回收。但結(jié)果并不是總和期望的那樣,比如有時候可能會出現(xiàn)一個循環(huán)引用,或者有時候需要內(nèi)存時可能要刪除對象的緩存。而弱引用(weak reference)是一個不會增加引用計數(shù)的對象句柄

引用

import weakref

'''
對象的弱引用要通過ref類來管理。要獲取原對象,可以調(diào)用引用對象
''' class RefObject:
def __del__(self):
print("del executed") obj = RefObject()
# 創(chuàng)建弱引用
r = weakref.ref(obj) print("obj:", obj) # obj: <__main__.RefObject object at 0x0000000002964470>
# 顯示關(guān)聯(lián)RefObject
print("ref:", r) # ref: <weakref at 0x000000000051BA48; to 'RefObject' at 0x0000000002964470> # 引用r加上(),等價于obj,因此得到RefObject的實(shí)例對象
print("ref()", r()) # ref() <__main__.RefObject object at 0x0000000002964470> # 刪除obj執(zhí)行析構(gòu)函數(shù)
del obj # del executed
# 之前說過調(diào)用r()等價于調(diào)用obj,但是obj被刪除了,所以返回None
# 從這里返回None也能看出這個弱引用是不會增加引用計數(shù)的
print("r():", r()) # r(): None

引用回調(diào)

import weakref

'''
ref構(gòu)造函數(shù)可以接受一個可選的回調(diào)函數(shù),刪除引用所指向的對象時就會調(diào)用這個回調(diào)函數(shù)
''' class RefObject:
def __del__(self):
print("del executed") def callback(reference):
print(f"callback : {reference}") obj = RefObject()
r = weakref.ref(obj, callback)
'''
當(dāng)引用所引用的原對象"死亡"時,這個回調(diào)會接受這個引用對象作為參數(shù)。
這種特性的一種用法就是從緩存中刪除弱引用對象。
''' print("obj:", obj) # obj: <__main__.RefObject object at 0x0000000002964630>
print("ref:", r) # ref: <weakref at 0x0000000001D2BA48; to 'RefObject' at 0x0000000002964630>
print("ref()", r()) # ref() <__main__.RefObject object at 0x0000000002964630> del obj # 刪除引用指向的對象
"""
del executed
callback : <weakref at 0x0000000001D2BA48; dead> 刪除obj,執(zhí)行回調(diào),顯示dead
"""
print("r():", r()) # r(): None

最終化對象

import weakref

'''
清理弱引用時要對資源完成更健壯的管理,可以使用finalize將回調(diào)與對象關(guān)聯(lián)。
finalize實(shí)例會一直保留(直到所關(guān)聯(lián)的對象被刪除),即使沒有保留最終化對象的引用
''' class RefObj:
def __del__(self):
print("xxx") def on_finalize(*args):
print(f"on_finalize: {args}") obj = RefObj()
weakref.finalize(obj, on_finalize, "callback的參數(shù)") del obj
'''
xxx
on_finalize: ('callback的參數(shù)',)
'''
# finalize的參數(shù)包括要跟蹤的對象,對象被垃圾回收時要調(diào)用的callback,以及參數(shù)(可以是位置參數(shù),也可以是關(guān)鍵字參數(shù)) # finalize實(shí)例對象還有一個atexit屬性,用來控制程序退出時是否調(diào)用這個回調(diào)(如果還未調(diào)用)
obj1 = RefObj()
f = weakref.finalize(obj1, on_finalize, "callback的參數(shù)")
# 默認(rèn)是調(diào)用回調(diào),但是將atexit設(shè)置為False會禁用這種行為
f.atexit = False
'''
不會有任何的輸出,注意:這里我雖然沒有顯示的刪除obj1,但也能夠說明結(jié)論
因為在f.atexit=True的情況下,即使不刪除也依舊會執(zhí)行callback。
原因是即使你不手動刪除,但是對象已經(jīng)被創(chuàng)建出來了,而程序結(jié)束的那一刻,也會執(zhí)行析構(gòu)函數(shù)的。因為對象總是要回收的,即使你不調(diào)用del,那么程序執(zhí)行完畢的時候也會自動調(diào)用。
所以默認(rèn)f.atexit = True是會打印的,但是現(xiàn)在沒有打印,所以確實(shí)被禁用了
'''
import weakref

'''
如果向finalize實(shí)例提供一個跟蹤對象的引用,這便會導(dǎo)致一個引用被保留,所以這個對象永遠(yuǎn)不會被垃圾回收
''' class RefObj:
def __del__(self):
print("xxx") def on_finalize(*args):
print(f"on_finalize: {args}") obj = RefObj()
obj_id = id(obj)
# 這里我將obj實(shí)例作為參數(shù)傳進(jìn)去了,這樣的后果就是obj不會被回收,即使你刪除了
f = weakref.finalize(obj, on_finalize, obj)
f.atexit = False # 刪除obj,讓obj不再指向之前的對象
del obj
import gc
# 獲取所有的對象
for o in gc.get_objects():
if id(o) == obj_id:
# 結(jié)果發(fā)現(xiàn)真的沒有被回收,因為引用不止obj一個,還有其它人在用
print("found uncollected object in gc") # found uncollected object in gc

代理

import weakref

'''
有時候使用代理比使用弱引用更方便。使用代理可以像使用原對象一樣,而且不要求在訪問對象之前先調(diào)用代理。
這說明,可以將代理傳遞到一個庫,而這個庫并不知道它接收的是一個代理而不是真正的一個對象。
''' class RefObj: def __init__(self, name):
self.name = name def __del__(self):
print("xxx") obj = RefObj("my obj")
r = weakref.ref(obj)
p = weakref.proxy(obj) # 可以看到引用加上()才相當(dāng)于原來的對象
# 而代理不需要,直接和原來的對象保持一致
print("via obj:", obj.name) # via obj: my obj
print("via ref:", r().name) # via ref: my obj
print("via proxy:", p.name) # via proxy: my obj del obj # xxx
try:
# 刪除對象之后,再調(diào)用引用,打印為None
print(r()) # None
# 但是如果調(diào)用代理的話,則會拋出一個ReferenceError
print(p)
except Exception as e:
print(e) # weakly-referenced object no longer exists

自定義類指定弱引用

當(dāng)我們自定義一個類的時候,如果為了省內(nèi)存,那么會不使用__dict__屬性,因為每一個類或者實(shí)例都會有一個自己的屬性字典__dict__,而我們知道字典使用的是哈希表,這是一個使用空間換時間的數(shù)據(jù)結(jié)構(gòu),因此如果想省內(nèi)存的話,那么我們通常的做法是指定__slots__屬性,這樣就不會再有__dict__屬性了。

class A:
__slots__ = ('name', 'age') def __init__(self, name, age):
# 此時在__init__里面,只能有self.name和self.age
# 這是因為我們在__slots__里面只指定了name和age
# 因此當(dāng)我們需要省內(nèi)存、并且屬性固定的時候,可以指定__slots__屬性
self.name = name
self.age = age def __str__(self):
return f"name is {self.name}, age is {self.age}" if __name__ == '__main__':
import weakref
a = A("hanser", 27)
try:
r = weakref.proxy(a)
except TypeError as e:
print(e) # cannot create weak reference to 'A' object

但是我們發(fā)現(xiàn)此時這個A的實(shí)例對象是沒有辦法被弱引用的,因為我們指定了__slots__,那么要怎么做呢?直接在__slots__里面加上一個屬性就好了。

class A:
# 多指定一個__weakref__,表示支持弱引用
__slots__ = ('name', 'age', '__weakref__') def __init__(self, name, age):
self.name = name
self.age = age def __str__(self):
return f"name is {self.name}, age is {self.age}" if __name__ == '__main__':
import weakref
a = A("hanser", 27)
r = weakref.proxy(a)
print(r)

可以看到此時就支持弱引用了。

總結(jié)

以上是生活随笔為你收集整理的weakref:对象的弱引用的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。