Python中的弱引用
Python 的内存管理算法使用引用计数机制进行垃圾收集,它跟踪所有可访问的对象。所有Python对象都包含一个引用计数字段,该字段计算有多少对象正在引用它。如果一个对象被另一个对象引用,则其计数器设置为非零数,并且该对象不能被垃圾回收。如果计数器达到零,垃圾收集器将释放该对象。
下面是一个简短的例子,说明我们如何在Python中找到任何对象的引用计数。
Python3
import ctypes
# list object which is referenced by
# my_list
my_list = [1, 2, 3]
# finding the id of list object
my_list_address = id(my_list)
# finds reference count of my_list
ref_count = ctypes.c_long.from_address(my_list_address).value
print(f"Reference count for my_list is: {ref_count}")
Python3
# importing weakref module
import weakref
# creating a class
class GFG(list):
pass
# creating object of a class
obj = GFG("Geeks")
# creating a normal list object
normal_list = obj
print(f"This is a normal object: {normal_list}")
# this returns a weak reference to obj
weak_list = weakref.ref(obj)
weak_list_obj = weak_list()
print(f"This is a object created using weak reference: {weak_list_obj}")
# creating a proxy of original object
proxy_list = weakref.proxy(obj)
print(f"This is a proxy object: {proxy_list}")
# printing the count of weak references
for objects in [normal_list, weak_list_obj, proxy_list]:
print(f"Number of weak references: {weakref.getweakrefcount(objects)}")
Python3
# import weakref module
import weakref
# creates a class
class GFG:
def __init__(self,data):
self.data = data
def __repr__(self):
return str(self.data)
# creates an object of class GFG
# (consider that this object is very
# large and has been stored in the cache)
value = GFG(5)
# creates a Weak Value Dictionary
weak_dict = weakref.WeakValueDictionary()
# inserting value into the dictionary
weak_dict["num"] = value
# getting the weak ref count
print(f'Weak reference count is: {weakref.getweakrefcount(weak_dict)}')
# deleting the weak dictionary
del weak_dict
# running this will generate error
# print(weak_dict)
输出:
Reference count for my_list is: 1
那么,既然我们已经了解了引用和垃圾收集的基础知识,那么让我们来看看什么是弱引用以及为什么需要它们?
什么是弱参考?
与我们上面讨论的引用不同,弱引用是一种不保护对象免于被垃圾回收的引用。为什么我们首先想要这样的东西?
弱引用有两个主要应用:
- 为大对象(弱字典)实现缓存。
- 减少循环引用的痛苦。
为了创建弱引用, Python为我们提供了一个名为weakref的模块。在使用 weakref 之前要记住的一点是,一些内置函数,如 tuple 或 int 不支持这一点。 list和dict支持是其中之一,但我们可以通过子类化添加支持。让我们详细讨论应用程序。
弱引用模块
有时,一个大对象存储在缓存中,因此不需要保持它处于活动状态。假设您有大量图像对象,它们被用作映射到图像的键,因此这些对象将保持活动状态。
幸运的是, weakref模块提供了称为WeakKeyDictionary的东西,并且WeakValueDictionary不会让对象在它们出现在映射对象中时保持活动状态。
weakref模块提供了以下类和方法:
- class weakref.ref(object[, callback]) – 这将返回对对象的弱引用。
- weakref.proxy( object [, callback ]) –这会返回一个使用弱引用的对象的代理。
- weakref.getweakrefcount( object ) – 返回引用object的弱引用和代理的数量。
- weakref.getweakrefs( object ) – 返回引用 object 的所有弱引用和代理对象的列表。
让我们通过一些例子来理解这项工作:
示例 1:
在下面给出的示例中,我们创建了一个普通列表对象、一个弱引用列表对象和一个代理列表对象,并为所有这些对象打印弱引用计数。
Python3
# importing weakref module
import weakref
# creating a class
class GFG(list):
pass
# creating object of a class
obj = GFG("Geeks")
# creating a normal list object
normal_list = obj
print(f"This is a normal object: {normal_list}")
# this returns a weak reference to obj
weak_list = weakref.ref(obj)
weak_list_obj = weak_list()
print(f"This is a object created using weak reference: {weak_list_obj}")
# creating a proxy of original object
proxy_list = weakref.proxy(obj)
print(f"This is a proxy object: {proxy_list}")
# printing the count of weak references
for objects in [normal_list, weak_list_obj, proxy_list]:
print(f"Number of weak references: {weakref.getweakrefcount(objects)}")
输出:
This is a normal object: [‘G’, ‘e’, ‘e’, ‘k’, ‘s’]
This is a object created using weak reference: [‘G’, ‘e’, ‘e’, ‘k’, ‘s’]
This is a proxy object: [‘G’, ‘e’, ‘e’, ‘k’, ‘s’]
Number of weak references: 2
Number of weak references: 2
Number of weak references: 0
由于普通对象具有对弱引用对象的引用,因此它们的弱引用计数均为 2,但由于 proxy_object 是从弱引用创建的代理,因此它没有引用计数。
示例 2:
在这个例子中,我们将看到如何使用我们在文章前面讨论过的WeakValueDictionary 。
Python3
# import weakref module
import weakref
# creates a class
class GFG:
def __init__(self,data):
self.data = data
def __repr__(self):
return str(self.data)
# creates an object of class GFG
# (consider that this object is very
# large and has been stored in the cache)
value = GFG(5)
# creates a Weak Value Dictionary
weak_dict = weakref.WeakValueDictionary()
# inserting value into the dictionary
weak_dict["num"] = value
# getting the weak ref count
print(f'Weak reference count is: {weakref.getweakrefcount(weak_dict)}')
# deleting the weak dictionary
del weak_dict
# running this will generate error
# print(weak_dict)
输出:
Weak reference count is: 1
在上面的示例中,我们假设有一个非常大的对象已放置在缓存中,因此我们创建了一个弱 ref 字典来存储该键和值对,以便对其进行垃圾收集。