Python之weakref模塊的使用


weakref模塊的作用

    weakref模塊支持對象的弱引用。正常的引用會增加對象的引用數,並避免它被垃圾回收。但結果並不是如期望中那樣,比如有時可能會出現一個循環引用,
或者有時需要內存時可能要刪除對象的緩存。弱引用是一個不能避免對象被自動清理的對象句柄。

1、對象的弱引用

import weakref


class ExpensiveObject:

    def __del__(self):
        print('(Deleting {})'.format(self))


obj = ExpensiveObject()
r = weakref.ref(obj)

print('obj:', obj)
print('ref:', r)
print('r():', r())

print('deleting obj')
del obj
print('r():', r())
weakref_ref.py

運行效果

obj: <__main__.ExpensiveObject object at 0x000001E72262EB88>
ref: <weakref at 0x000001E722633598; to 'ExpensiveObject' at 0x000001E72262EB88>
r(): <__main__.ExpensiveObject object at 0x000001E72262EB88>
deleting obj
(Deleting <__main__.ExpensiveObject object at 0x000001E72262EB88>)
r(): None

2、對象引用回調

import weakref

class ExpensiveObject:

    def __del__(self):
        print('(Deleting {})'.format(self))

def callback(reference):
    """刪除對象后,進行回調"""
    print('callback({!r})'.format(reference))


obj = ExpensiveObject()
r = weakref.ref(obj, callback)

print('obj:', obj)
print('ref:', r)
print('r():', r())

print('deleting obj')
del obj
print('r():', r())
weakref_ref_callback.py

運行效果

obj: <__main__.ExpensiveObject object at 0x000002819406EE08>
ref: <weakref at 0x0000028194073688; to 'ExpensiveObject' at 0x000002819406EE08>
r(): <__main__.ExpensiveObject object at 0x000002819406EE08>
deleting obj
(Deleting <__main__.ExpensiveObject object at 0x000002819406EE08>)
callback(<weakref at 0x0000028194073688; dead>)
r(): None

 3、清理的弱引用,最終回收處理

import weakref


class ExpensiveObject:

    def __del__(self):
        print('(Deleting {})'.format(self))


def on_finalize(*args):
    print('on_finalize({!r})'.format(args))


obj = ExpensiveObject()
weakref.finalize(obj, on_finalize, 'extra argument')

del obj
weakref_finalize.py

運行效果

(Deleting <__main__.ExpensiveObject object at 0x00000188B703EB88>)
on_finalize(('extra argument',))

4、atexit設置布爾值,來控制程序退出時,是否回調函數

import sys
import weakref

class ExpensiveObject:

    def __del__(self):
        print('(Deleting {})'.format(self))

def on_finalize(*args):
    print('on_finalize({!r})'.format(args))

obj = ExpensiveObject()
f = weakref.finalize(obj, on_finalize, 'extra argument')
f.atexit = bool(int(sys.argv[1]))
weakref_finalize_atexit.py

 運行效果

python3 weakref_finalize_atexit.py 1
on_finalize(('extra argument',))
(Deleting <__main__.ExpensiveObject object at 0x00000295B11FED08>)



python3 weakref_finalize_atexit.py 0

 5、在finalize引用對象的時候,del對象,內存中的對象是不會被gc回收的

import gc
import weakref

class ExpensiveObject:

    def __del__(self):
        print('(Deleting {})'.format(self))

def on_finalize(*args):
    print('on_finalize({!r})'.format(args))

obj = ExpensiveObject()
obj_id = id(obj)

f = weakref.finalize(obj, on_finalize, obj)
f.atexit = False

del obj

for o in gc.get_objects():
    if id(o) == obj_id:
        print('在GC中發現未收集的對象')
weakref_finalize_reference.py

運行效果

在GC中發現未收集的對象

 6、finalize提供callable是實例obj的一個綁定方法,所以最終化方法保留了obj的一個引用,它不能被刪除和被回收。

import gc
import weakref

class ExpensiveObject:

    def __del__(self):
        print('(Deleting {})'.format(self))

    def do_finalize(self):
        print('do_finalize')

obj = ExpensiveObject()
obj_id = id(obj)

f = weakref.finalize(obj, obj.do_finalize)
f.atexit = False

del obj

for o in gc.get_objects():
    if id(o) == obj_id:
        print('在GC中發現未收集的對象')
eakref_finalize_reference_method.py

 運行效果

在GC中發現未收集的對象

7、代理弱引用

import weakref


class ExpensiveObject:

    def __init__(self, name):
        self.name = name

    def __del__(self):
        print('(Deleting {})'.format(self))


obj = ExpensiveObject('My Object')
r = weakref.ref(obj)
p = weakref.proxy(obj)

print('via obj:', obj.name)
print('via ref:', r().name)
print('via proxy:', p.name)
del obj
print('via proxy:', p.name)
weakref_proxy.py

運行效果

via obj: My Object
via ref: My Object
via proxy: My Object
(Deleting <__main__.ExpensiveObject object at 0x000001FF9D3FECC8>)
Traceback (most recent call last):
  File "xxxx", line 21, in <module>
    print('via proxy:', p.name)
ReferenceError: weakly-referenced object no longer exists  #代理對象不存在的時候,報異常

8、弱引用緩存對象

from pprint import pprint
import weakref
import gc

gc.set_debug(gc.DEBUG_UNCOLLECTABLE)


class ExpensiveObject:

    def __init__(self, name):
        self.name = name

    def __repr__(self):
        return 'ExpensiveObject({})'.format(self.name)

    def __del__(self):
        print('    (Deleting {})'.format(self))


def demo(cache_factory):
    # 保持對象,以便任何弱引用,不會立即移除
    all_refs = {}
    # 使用工廠創建緩存
    print('CACHE TYPE:', cache_factory)
    cache = cache_factory()
    for name in ['one', 'two', 'three']:
        o = ExpensiveObject(name)
        cache[name] = o
        all_refs[name] = o
        del o  # decref

    print('  all_refs =', end=' ')
    pprint(all_refs)
    print('\n  Before, cache contains:', list(cache.keys()))
    for name, value in cache.items():
        print('    {} = {}'.format(name, value))
        del value  # decref

    # 刪除對對象的所有引用,但緩存除外
    print('\n  Cleanup:')
    del all_refs
    gc.collect()

    print('\n  After, cache contains:', list(cache.keys()))
    for name, value in cache.items():
        print('    {} = {}'.format(name, value))
    print('  demo returning')
    return


demo(dict)
print()

demo(weakref.WeakValueDictionary)
weakref_valuedict.py

 

 運行效果

CACHE TYPE: <class 'dict'>
  all_refs = {'one': ExpensiveObject(one),
 'three': ExpensiveObject(three),
 'two': ExpensiveObject(two)}

  Before, cache contains: ['one', 'two', 'three']
    one = ExpensiveObject(one)
    two = ExpensiveObject(two)
    three = ExpensiveObject(three)

  Cleanup:

  After, cache contains: ['one', 'two', 'three']
    one = ExpensiveObject(one)
    two = ExpensiveObject(two)
    three = ExpensiveObject(three)
  demo returning
    (Deleting ExpensiveObject(one))
    (Deleting ExpensiveObject(two))
    (Deleting ExpensiveObject(three))

CACHE TYPE: <class 'weakref.WeakValueDictionary'>
  all_refs = {'one': ExpensiveObject(one),
 'three': ExpensiveObject(three),
 'two': ExpensiveObject(two)}

  Before, cache contains: ['one', 'two', 'three']
    one = ExpensiveObject(one)
    two = ExpensiveObject(two)
    three = ExpensiveObject(three)

  Cleanup:
    (Deleting ExpensiveObject(one))
    (Deleting ExpensiveObject(two))
    (Deleting ExpensiveObject(three))

  After, cache contains: []
  demo returning


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM