📜  Python中的弱引用

📅  最后修改于: 2022-05-13 01:55:49.541000             🧑  作者: Mango

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 不支持这一点。 listdict支持是其中之一,但我们可以通过子类化添加支持。让我们详细讨论应用程序。

弱引用模块

有时,一个大对象存储在缓存中,因此不需要保持它处于活动状态。假设您有大量图像对象,它们被用作映射到图像的键,因此这些对象将保持活动状态。

幸运的是, 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)}")

输出:

由于普通对象具有对弱引用对象的引用,因此它们的弱引用计数均为 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 字典来存储该键和值对,以便对其进行垃圾收集。