Python - 弱引用



Python 在实施垃圾回收策略时使用引用计数机制。每当引用内存中的对象时,计数都会增加 1。另一方面,当删除引用时,计数将递减 1。如果在后台运行的垃圾回收器发现任何 count 为 0 的对象,则会将其删除并回收占用的内存。

弱引用是不保护对象不被垃圾回收的引用。当您需要为大型对象实现缓存时,以及在希望减少循环引用的 Pain 的情况下,它被证明很重要。

为了创建弱引用,Python 为我们提供了一个名为 weakref 的模块。

此模块中的 ref Management 对对象的弱引用。调用时,它将检索原始对象。

要创建弱引用 -


 weakref.ref(class())


import weakref
class Myclass:
	 	def __del__(self):
	 	 	 print('(Deleting {})'.format(self))
obj = Myclass()
r = weakref.ref(obj)

print('object:', obj)
print('reference:', r)
print('call r():', r())

print('deleting obj')
del obj
print('r():', r())

在删除引用对象后调用引用对象将返回 None。

它将产生以下输出 -

object: <__main__.Myclass object at 0x00000209D7173290>
reference: <weakref at 0x00000209D7175940; to 'Myclass' at
0x00000209D7173290>
call r(): <__main__.Myclass object at 0x00000209D7173290>
deleting obj
(Deleting <__main__.Myclass object at 0x00000209D7173290>)
r(): None

callback 函数

ref 类的构造函数有一个称为 callback function 的可选参数,当引用的对象被删除时,将调用该参数。


import weakref
class Myclass:
	 	def __del__(self):
	 	 	 print('(Deleting {})'.format(self))
def mycallback(rfr):
	 	"""called when referenced object is deleted"""
	 	print('calling ({})'.format(rfr))
obj = Myclass()
r = weakref.ref(obj, mycallback)

print('object:', obj)
print('reference:', r)
print('call r():', r())

print('deleting obj')
del obj
print('r():', r())

它将产生以下输出 -

object: <__main__.Myclass object at 0x000002A0499D3590>
reference: <weakref at 0x000002A0499D59E0; to 'Myclass' at
0x000002A0499D3590>
call r(): <__main__.Myclass object at 0x000002A0499D3590>
deleting obj
(Deleting <__main__.Myclass object at 0x000002A0499D3590>)
calling (<weakref at 0x000002A0499D59E0; dead>)
r(): None

None 完成对象

weakref 模块提供了 finalize 类。当垃圾回收器收集对象时,将调用其对象。该对象将一直存在,直到调用引用对象为止。


import weakref
class Myclass:
	 	def __del__(self):
	 	 	 print('(Deleting {})'.format(self))

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

obj = Myclass()
r = weakref.finalize(obj, finalizer, "Call to finalizer")

print('object:', obj)
print('reference:', r)
print('call r():', r())

print('deleting obj')
del obj
print('r():', r())

它将产生以下输出 -

object: <__main__.Myclass object at 0x0000021015103590>
reference: <finalize object at 0x21014eabe80; for 'Myclass' at
0x21015103590>
Finalizer('Call to finalizer',))
call r(): None
deleting obj
(Deleting <__main__.Myclass object at 0x0000021015103590>)
r(): None

weakref 模块提供 WeakKeyDictionary WeakValueDictionary 类。它们不会使对象在映射对象中显示时保持活动状态。它们更适合创建多个对象的缓存。

弱键字典

Mapping 弱引用键的类。当不再有对键的强引用时,字典中的条目将被丢弃。

WeakKeyDictionary 类的实例是使用现有字典或没有任何参数创建的,其功能与普通字典相同,可以向其添加和删除映射条目。

在下面给出的代码中,创建了三个 Person 实例。然后,它使用字典创建 WeakKeyDictionary 的实例,其中键是 Person 实例,值是 Person 的名称。

我们调用 keyrefs() 方法来检索弱引用。删除对 Peron1 的引用时,将再次打印字典键。新的 Person 实例将添加到具有弱引用键的字典中。最后,我们再次打印字典的键。


import weakref

class Person:
	 	def __init__(self, person_id, name, age):
	 	 	 self.emp_id = person_id
	 	 	 self.name = name
	 	 	 self.age = age

	 	def __repr__(self):
	 	 	 return "{} : {} : {}".format(self.person_id, self.name, self.age)
Person1 = Person(101, "Jeevan", 30)
Person2 = Person(102, "Ramanna", 35)
Person3 = Person(103, "Simran", 28)
weak_dict = weakref.WeakKeyDictionary({Person1: Person1.name, Person2: Person2.name, Person3: Person3.name})
print("Weak Key Dictionary : {}\n".format(weak_dict.data))
print("Dictionary Keys : {}\n".format([key().name for key in weak_dict.keyrefs()]))
del Person1
print("Dictionary Keys : {}\n".format([key().name for key in weak_dict.keyrefs()]))
Person4 = Person(104, "Partho", 32)
weak_dict.update({Person4: Person4.name})

print("Dictionary Keys : {}\n".format([key().name for key in weak_dict.keyrefs()]))

它将产生以下输出 -

Weak Key Dictionary : {<weakref at 0x7f542b6d4180; to 'Person' at 0x7f542b8bbfd0>: 'Jeevan', <weakref at 0x7f542b6d5530; to 'Person' at 0x7f542b8bbeb0>: 'Ramanna', <weakref at 0x7f542b6d55d0; to 'Person' at 0x7f542b8bb7c0>: 'Simran'}

Dictionary Keys : ['Jeevan', 'Ramanna', 'Simran']

Dictionary Keys : ['Ramanna', 'Simran']

Dictionary Keys : ['Ramanna', 'Simran', 'Partho']

WeakValueDictionary

Mapping 弱引用值的类。当不再存在对该值的强引用时,字典中的条目将被丢弃。

我们将演示如何使用 WeakValueDictionary 创建具有弱引用值的字典。

该代码与前面的示例类似,但这次我们使用 Person name 作为键,使用 Person 实例作为值。我们使用 valuerefs() 方法来检索字典的弱引用值。


import weakref

class Person:
	 	def __init__(self, person_id, name, age):
	 	 	 self.emp_id = person_id
	 	 	 self.name = name
	 	 	 self.age = age
	 	
	 	def __repr__(self):
	 	 	 return "{} : {} : {}".format(self.person_id, self.name, self.age)

Person1 = Person(101, "Jeevan", 30)
Person2 = Person(102, "Ramanna", 35)
Person3 = Person(103, "Simran", 28)

weak_dict = weakref.WeakValueDictionary({Person1.name:Person1, Person2.name:Person2, Person3.name:Person3})
print("Weak Value Dictionary : {}\n".format(weak_dict.data))
print("Dictionary Values : {}\n".format([value().name for value in weak_dict.valuerefs()]))
del Person1
print("Dictionary Values : {}\n".format([value().name for value in weak_dict.valuerefs()]))
Person4 = Person(104, "Partho", 32)
weak_dict.update({Person4.name: Person4})
print("Dictionary Values : {}\n".format([value().name for value in weak_dict.valuerefs()]))

它将产生以下输出 -

Weak Value Dictionary : {'Jeevan': <weakref at 0x7f3af9fe4180; to 'Person' at 0x7f3afa1c7fd0>, 'Ramanna': <weakref at 0x7f3af9fe5530; to 'Person' at 0x7f3afa1c7eb0>, 'Simran': <weakref at 0x7f3af9fe55d0; to 'Person' at 0x7f3afa1c77c0>}

Dictionary Values : ['Jeevan', 'Ramanna', 'Simran']

Dictionary Values : ['Ramanna', 'Simran']

Dictionary Values : ['Ramanna', 'Simran', 'Partho']