WeakSet 中的WeakMethod

问题描述 投票:0回答:1

我想使用

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
的功能?

python python-3.x weak-references
1个回答
0
投票

这是我在观察者模式上下文中使用的当前“明显”解决方法:

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
的更优雅的解决方案。

© www.soinside.com 2019 - 2024. All rights reserved.