python–基础知识点–弱引用

python–基础知识点–弱引用本文详细介绍了 Python 中弱引用的概念和应用场景 包括缓存 监听器模式 对象关系映射及临时引用

大家好,欢迎来到IT知识分享网。

1.概念

弱引用:不会增加对象的引用数量,不会妨碍所指对象(referent)被当作垃圾回收。弱引用可用于解决循环引用的问题。

弱引用在缓存应用中很有用,因为不想仅仅因为对象被缓存引用着而始终被保持。

Python中,使用弱引用(weak reference)主要有以下几个场景:

  • 缓存:当需要缓存对象但不希望这些对象被缓存所阻止垃圾回收时,可以使用弱引用。弱引用允许垃圾回收器在没有其他引用的情况下自动删除对象。这在需要实现缓存的场景中非常有用。
  • 监听器模式:当一个对象需要监听另一个对象的状态变化,但不需要保持对被监听对象的强引用时,可以使用弱引用。这样,在被监听对象被垃圾回收时,监听器对象也可以自动被释放。
  • 对象关系映射(ORM):在ORM框架中,为了避免循环引用和内存泄漏,通常会使用弱引用来处理对象之间的关系。比如,一个父对象包含对子对象的引用,而子对象也包含对父对象的引用,为了防止循环引用导致无法释放内存,可以使用弱引用来保存对父对象的引用。
  • 临时引用:当需要在某些情况下暂时引用一个对象,但又不希望该引用影响到垃圾回收的行为时,可以使用弱引用。这样,在没有其他强引用的情况下,对象可以被垃圾回收。

需要注意的是,弱引用对象并不能保证其引用的对象一定会被垃圾回收。它只是提供了一种机制,使垃圾回收器能够在没有其他强引用的情况下自动删除对象。垃圾回收的具体时机仍然取决于垃圾回收器的策略和算法。

2.弱引用的创建
2.1创建弱引用

通过调用 weakref 模块的 ref(obj[,callback]) 来创建一个弱引用,obj 是你想弱引用的对象, callback 是一个可选的函数,当因没有引用导致 Python 要销毁这个对象时调用。回调函数callback要求单个参数(弱引用的对象)。

一旦你有了一个对象的弱引用,你就能通过调用弱引用来获取被弱引用的对象。

>>> import sys >>> import weakref >>> class Man(): ... def __init__(self, name): ... self.name = name ... >>> man0 = Man('zhe') # 增加一个引用 count = 1  >>> sys.getrefcount(man0) 2 >>> r = weakref.ref(man0) # 增加一个弱引用 count = 1  >>> sys.getrefcount(man0) 2 >>> r # 获取弱引用所指向的对象 <weakref at 0x0000026AF; to 'Man' at 0x0000026AF398C710> >>> man1 = r() >>> man0 is man1 True >>> sys.getrefcount(man0) 3 >>> man0 = None >>> man1 = None >>> r # 当对象引用计数为零时,弱引用失效。 <weakref at 0x0000026AF; dead> 

weakref.ref 类的实例获取所指对象,提供的是底层接口,尽量不要手动创建并处理weakref.ref实例。

注:

  • 上面的代码中,我们使用 sys 包中的 getrefcount() 来查看某个对象的引用计数。需要注意的是,当使用某个引用作为参数,传递给 getrefcount() 时,参数实际上创建了一个临时的引用。因此, getrefcount() 所得到的结果,会比期望的多 1 。
  • 一旦没有了对这个对象的其它的引用,调用弱引用将返回None,因为Python已经销毁了这个对象。 注意:大部分的对象不能通过弱引用来访问。
  • weakref 模块中的 getweakrefcount(obj) 和 getweakrefs(obj) 分别返回弱引用数和关于所给对象的引用列表。
  • 弱引用对于创建对象(这些对象很费资源)的缓存是有用的。
  • 对弱引用的使用来访问原对象要通过 weakref() 的形式。 其实可以创建代理对象对原对象进行访问。
2.2创建代理对象

代理对象 是弱引用对象,它们的行为就像它们所引用的对象,这就便于你不必首先调用弱引用来访问背后的对象。通过weakref模块的proxy(obj[,callback])函数来创建代理对象。使用代理对象就如同使用对象本身一样:

相比于创建弱引用 在调用上完全等同于

>>> import sys >>> import weakref >>> class Man(): ... def __init__(self, name): ... self.name = name ... >>> def callback_ref(self): ... print (self) ... print ("callback_ref") ... >>> def callback_proxy(self): ... print (self) ... print ("callback_proxy") ... >>> man = Man('zhe') # 引用计数 +1 >>> sys.getrefcount(man) 2 >>> man_ref = weakref.ref(man, callback_ref) # 弱引用 引用计数不变 >>> sys.getrefcount(man) 2 >>> man_ref # 弱引用对象 <weakref at 0x0000019A; to 'Man' at 0x0000019A6367C668> >>> man_ref.name # 对原对象的访问形式错误 Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'weakref' object has no attribute 'name' >>> man_ref().name # 正确的对原对象的访问形式 'zhe' >>> man_proxy = weakref.proxy(man, callback_proxy) # 使用代理 引用计数不变 >>> sys.getrefcount(man) 2 >>> man_proxy # 代理对象 <weakproxy at 0x0000019A634D6BD8 to Man at 0x0000019A6367C668> >>> man_proxy.name # 访问形式与原引用相同 'zhe' >>> del man # 注 Exception ignored in: <function callback_proxy at 0x0000019AB8> Traceback (most recent call last): File "<stdin>", line 2, in callback_proxy ReferenceError: weakly-referenced object no longer exists <weakref at 0x0000019A; dead> callback_ref 
2.3缓存对象

一般不要直接创建处理 weakref.ref 实例,最好使用 weakref 集合和 finalize,即 WeakKeyDictionary、WeakValueDictionary、WeakSet、finalize。

2.3.1 WeakValueDictionary

WeakValueDictionary 是Python标准库中weakref模块提供的一个类,它是一种特殊的字典,它的值是弱引用对象。这意味着,如果一个值对象在程序中没有其他引用,那么它可以被垃圾回收并从字典中自动删除。

以下是WeakValueDictionary的使用示例:

import weakref # 创建一个WeakValueDictionary对象 d = weakref.WeakValueDictionary() # 定义一个类 class MyClass: def __init__(self, name): self.name = name # 创建实例对象,并将其作为值添加到字典中 obj1 = MyClass('Object 1') obj2 = MyClass('Object 2') d['key1'] = obj1 d['key2'] = obj2 # 输出字典的内容 print(d) # 输出: {'key1': <__main__.MyClass object at 0x...>, 'key2': <__main__.MyClass object at 0x...>} # 删除原始对象的引用 del obj1 # 等待垃圾回收 # 输出字典的内容 print(d) # 输出: {'key2': <__main__.MyClass object at 0x...>} 

在这个示例中,我们创建了一个WeakValueDictionary对象d。然后,我们定义了一个MyClass类,并创建了两个实例对象obj1和obj2。我们将这两个对象作为值添加到字典d中。

当我们删除obj1的引用之后,obj1没有其他引用了,它可以被垃圾回收。由于d中的值是弱引用对象,当obj1被垃圾回收时,对应的键值对’key1’: obj1也会从字典中自动删除。

因此,在等待垃圾回收之后,我们可以看到字典中只剩下’key2’: obj2这个键值对。这表明WeakValueDictionary将自动处理那些不再有其他引用的值对象的删除。

2.3.2 WeakKeyDictionary

WeakKeyDictionary是Python标准库中weakref模块提供的另一个类,它是一种特殊的字典,它的键是弱引用对象。这意味着,如果一个键对象在程序中没有其他引用,那么它可以被垃圾回收并从字典中自动删除。

以下是WeakKeyDictionary的使用示例:

import weakref # 创建一个WeakKeyDictionary对象 d = weakref.WeakKeyDictionary() # 定义一个类 class MyClass: def __init__(self, name): self.name = name # 创建实例对象,并将其作为键添加到字典中 obj1 = MyClass('Object 1') obj2 = MyClass('Object 2') d[obj1] = 'Value 1' d[obj2] = 'Value 2' # 输出字典的内容 print(d) # 输出: {<__main__.MyClass object at 0x...>: 'Value 1', <__main__.MyClass object at 0x...>: 'Value 2'} # 删除原始对象的引用 del obj1 # 等待垃圾回收 # 输出字典的内容 print(d) # 输出: {<__main__.MyClass object at 0x...>: 'Value 2'} 

在这个示例中,我们创建了一个WeakKeyDictionary对象d。然后,我们定义了一个MyClass类,并创建了两个实例对象obj1和obj2。我们将这两个对象作为键添加到字典d中。

当我们删除obj1的引用之后,obj1没有其他引用了,它可以被垃圾回收。由于d中的键是弱引用对象,当obj1被垃圾回收时,对应的键值对obj1: ‘Value 1’也会从字典中自动删除。

因此,在等待垃圾回收之后,我们可以看到字典中只剩下obj2: ‘Value 2’这个键值对。这表明WeakKeyDictionary将自动处理那些不再有其他引用的键对象的删除。

2.3.3 WeakSet

WeakSet是Python标准库中weakref模块提供的另一个类,它是一种特殊的集合,其中的元素是弱引用对象。这意味着,如果一个元素对象在程序中没有其他引用,那么它可以被垃圾回收并从集合中自动删除。

import weakref # 创建一个WeakSet对象 ws = weakref.WeakSet() # 定义一个类 class MyClass: def __init__(self, name): self.name = name # 创建实例对象 obj1 = MyClass('Object 1') obj2 = MyClass('Object 2') # 将实例对象添加到WeakSet中 ws.add(obj1) ws.add(obj2) # 输出WeakSet的内容 print(ws) # 输出: {<__main__.MyClass object at 0x...>, <__main__.MyClass object at 0x...>} # 删除原始对象的引用 del obj1 # 等待垃圾回收 # 输出WeakSet的内容 print(ws) # 输出: {<__main__.MyClass object at 0x...>} 

在这个示例中,我们创建了一个WeakSet对象ws。然后,我们定义了一个MyClass类,并创建了两个实例对象obj1和obj2。我们将这两个对象添加到ws中。

当我们删除obj1的引用之后,obj1没有其他引用了,它可以被垃圾回收。由于ws中的元素是弱引用对象,当obj1被垃圾回收时,对应的元素也会从集合中自动删除。

因此,在等待垃圾回收之后,我们可以看到集合中只剩下obj2这个元素。这表明WeakSet将自动处理那些不再有其他引用的元素对象的删除。

2.3.4 finalize

finalize是Python标准库中weakref模块提供的一个函数,它可以用于注册在对象被垃圾回收时调用的回调函数。这个函数可以用来执行一些清理操作,例如关闭文件或释放资源。

以下是finalize函数的使用示例:

import weakref # 定义一个类 class MyClass: def __init__(self, name): self.name = name def cleanup(self): print(f'Cleaning up { 
     self.name}') # 创建实例对象 obj1 = MyClass('Object 1') # 注册回调函数 finalizer = weakref.finalize(obj1, obj1.cleanup) # 输出对象是否还存活 print(finalizer.alive) # 输出: True # 删除原始对象的引用 del obj1 # 等待垃圾回收 # 输出对象是否还存活 print(finalizer.alive) # 输出: False # 回调函数被调用 # 输出: Cleaning up Object 1 

在这个示例中,我们创建了一个MyClass类,并创建了一个实例对象obj1。我们通过weakref.finalize函数将obj1.cleanup方法注册为obj1对象的回调函数。

当我们删除obj1的引用之后,obj1没有其他引用了,它可以被垃圾回收。在对象被垃圾回收时,注册的回调函数obj1.cleanup会被调用。

因此,在等待垃圾回收之后,我们可以看到回调函数被调用,并输出”Cleaning up Object 1″。这表明finalize函数可以在对象被垃圾回收时执行所注册的回调函数。

免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/119081.html

(0)
上一篇 2025-11-08 09:20
下一篇 2025-11-08 09:33

相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注微信