weakref.WeakSet
的功能,但在这个集合中我想存储绑定方法,所以我必须使用weakref.WeakMethod
。
这是一个精简的示例:
import weakref
class C:
def method(self): pass
ci = C()
print("weakMethod:", weakref.WeakMethod(ci.method))
print("s1:", weakref.WeakSet([C.method]))
print("s2:", weakref.WeakSet([ci.method]))
print("s3:", weakref.WeakSet([weakref.WeakMethod(ci.method)]))
这给了我(使用Python 3.12.2)
weakMethod: <weakref at 0x7f569e9308d0; to 'C' at 0x7f569e96dca0>
s1: {<weakref at 0x7f56ac12a520; to 'function' at 0x7f569e98ade0 (method)>}
s2: set()
s3: set()
正如您在第一行中看到的,
WeakMethod
按预期工作,但将其存储在 WeakSet
中会产生空的 s3
。
旁注:
s2
如预期为空,但存储对未绑定方法的弱引用(如s1
中所示)是可行的。
明显的解决方法:使用
set
代替 WeakSet
并复制其功能。
问题: 有没有更优雅的方式来结合
WeakSet
和 WeakMethod
的功能?
这是我在观察者模式上下文中使用的当前“明显”解决方法:
class Observable:
def __init__(self):
self.observers = set()
def observe(self, method):
def remote_observer(observer):
print(f"removed {observer} from observers")
self.observers.remove(observer)
self.observers.add(weakref.WeakMethod(method, remote_observer))
def unobserve(self, func):
self.observers.discard(func)
def call_observers(self):
for observer in self.observers:
observer()()
observable = Observable()
class ACME:
def __init__(self):
for _ in range(5):
observable.observe(self.observer)
def observer(self):
print("ACME observer called")
acme = ACME()
print("### expecting one observer to be called ###")
observable.call_observers()
del acme
print("### expecting no observer to be called ###")
observable.call_observers()
输出:
### expecting one observer to be called ###
ACME observer called
removed <weakref at 0x7f1240feee50; dead> from observers
### expecting no observer to be called ###
请注意,
set
做得很好,并将五个相等的观察者归结为单个观察者,并且 WeakMethod
在 del acme
之后删除了观察者。如果将 WeakMethod
替换为直接引用,它将保持 acme
及其观察者处于活动状态,尽管存在 del acme
(这正是我试图避免的)。
好的,这可行,但我很好奇您是否有使用
WeakSet
的更优雅的解决方案。