当前位置: 首页 > 面试题库 >

使用python WeakSet启用回调功能

司寇旺
2023-03-14
问题内容

我正在研究是否可以在python中实现简单的回调功能。我以为我可以为此使用weakref.WeakSet,但是显然我缺少了一些东西或被误解了。正如您在代码中看到的那样,我首先尝试使用“
ClassA”对象中的回调方法列表,但意识到这将使添加到回调列表中的对象保持活动状态。相反,我尝试使用weakref.WeakSet,但这也不起作用(至少不是这样)。最后四行代码中的注释说明了我想要发生的事情。

谁能帮我这个?

from weakref import WeakSet
class ClassA:
    def __init__(self):
        #self.destroyCallback=[]
        self.destroyCallback=WeakSet()
    def __del__(self):
        print('ClassA object %d is being destroyed' %id(self))
        for f in self.destroyCallback:
            f(self)
class ClassB:
    def destroyedObjectListener(self,obj):
        print('ClassB object %d is called because obj %d is being destroyed'%(id(self),id(obj)))
a1=ClassA()
a2=ClassA()
b=ClassB()

a1.destroyCallback.add(b.destroyedObjectListener)
#a1.destroyCallback.append(b.destroyedObjectListener)
print('destroyCallback len() of obj: %d is: %d'%(id(a1),len(a1.destroyCallback))) # should be 1

a2.destroyCallback.add(b.destroyedObjectListener)
#a2.destroyCallback.append(b.destroyedObjectListener)
print('destroyCallback len() of obj: %d is: %d'%(id(a2),len(a2.destroyCallback))) # should be 1

del a1 # Should call b.destroyedObjectListener(self) in its __del__ method

del b # should result in no strong refs to b so a2's WeakSet should automatically remove added item

print('destroyCallback len() of obj: %d is: %d'%(id(a2),len(a2.destroyCallback))) # should be 0
del a2 # Should call __del__ method

更新:基于接受的答案的解决方案可以在github上找到:git@github.com:thgis / PythonEvent.git


问题答案:

您不能创建对方法对象的弱引用。方法对象是 短暂的 ;
它们是在您访问实例上的名称时动态创建的。请参阅描述符howto的工作原理。

当您访问方法名称时,将为您创建一个 新的 方法对象,然后将该方法添加到中WeakSet,不再有对其的其他引用,因此垃圾回收很高兴再次对其进行清理。

您将不得不存储一些不太瞬变的东西。存储实例对象本身可以工作,然后在已注册的回调中调用预定义方法:

def __del__(self):
    for f in self.destroyCallback:
        f.destroyedObjectListener(self)

并注册:

a1.destroyCallback.add(b)

您还可以通过给它一个方法使b 自己 成为可调用的__call__

class ClassB:
    def __call__(self,obj):
        print('ClassB object %d is called because obj %d '
              'is being destroyed' % (id(self), id(obj)))

另一种方法是存储对基础函数对象的引用以及对实例的引用:

import weakref


class ClassA:
    def __init__(self):
        self._callbacks = []

    def registerCallback(self, callback):
        try:
            # methods
            callback_ref = weakref.ref(callback.__func__), weakref.ref(callback.__self__)
        except AttributeError:
            callback_ref = weakref.ref(callback), None
        self._callbacks.append(callback_ref)

    def __del__(self):
        for callback_ref in self._callbacks:
            callback, arg = callback_ref[0](), callback_ref[1]
            if arg is not None:
                # method
                arg = arg()
                if arg is None:
                    # instance is gone
                    continue
                callback(arg, self)
                continue
            else:
                if callback is None:
                    # callback has been deleted already
                    continue
                callback(self)

演示:

>>> class ClassB:
...     def listener(self, deleted):
...         print('ClassA {} was deleted, notified ClassB {}'.format(id(deleted), id(self)))
... 
>>> def listener1(deleted):
...     print('ClassA {} was deleted, notified listener1'.format(id(deleted)))
... 
>>> def listener2(deleted):
...     print('ClassA {} was deleted, notified listener2'.format(id(deleted)))
... 
>>> # setup, one ClassA and 4 listeners (2 methods, 2 functions)
... 
>>> a = ClassA()
>>> b1 = ClassB()
>>> b2 = ClassB()
>>> a.registerCallback(b1.listener)
>>> a.registerCallback(b2.listener)
>>> a.registerCallback(listener1)
>>> a.registerCallback(listener2)
>>> 
>>> # deletion, we delete one instance of ClassB, and one function
... 
>>> del b1
>>> del listener1
>>> 
>>> # Deleting the ClassA instance will only notify the listeners still remaining
... 
>>> del a
ClassA 4435440336 was deleted, notified ClassB 4435541648
ClassA 4435440336 was deleted, notified listener2


 类似资料:
  • 问题内容: 我试图用Python在用户输入命令的地方做一个“游戏”。但是,我不知道您是否可以将该输入用作函数名。这是我目前的努力: 在这里,输入是移动的,就像我想尝试调用该函数一样(潜在的最终用户可能会)。但是,出现以下错误: 我想知道是否有什么方法可以允许用户在游戏中“移动”,程序通过调用“移动”功能来实现。 问题答案: 看起来您正在使用python3.x,其中返回了一个字符串。要恢复pytho

  • 问题内容: 我正在编写一个Wordpress MU插件,它在每个帖子中都包含一个链接,并且我想在用户单击此链接时使用ajax调用插件功能之一,然后使用该功能的输出动态更新链接文本。 。 我陷入了ajax查询。我已经有了这种复杂的,显然有点乱的方法,但是它不是很有效。在插件中包含Ajax功能的“正确”或“ wordpress”方式是什么? (下面是我当前的黑客代码。单击生成链接时,在wp页面中得到的

  • 回调使用方式 登录控制台https://www.wenjiangs.com/doc/QSfBOXSPconsole/, 进入系统管理下的回调通知,点击添加。 直播回调说明 直播开始时回调 { "channel_id":"d5zjyp40", "call":"publish", "event":"publish" } 直播结束时回调 { "channel_id":"

  • 问题内容: 我是一个node.js和express.js新手。这个问题看似愚蠢,但我真的很困惑。 我正在尝试使用通行证配置本地策略身份验证。如官方文档所示,我们可以通过以下代码来计算此本地策略, 我的困惑是关于回调函数。当官方文档在路由处理程序中将此中间策略用作中间件时,无需为此回调传递function参数。 因此,如果不提供function参数,此回调函数是否不为null?如果不是,那么该回调函

  • 问题内容: 我有一个用Python编写的控制台程序。它使用以下命令询问用户问题: 如何测试包含对using的调用的函数?我不想强迫测试人员多次输入文本只是为了完成一次测试运行。 问题答案: 您可能应该模拟内置功能,可以在每次测试后使用提供的功能还原为原始功能。 更好的解决方案是将模块与一起使用。这样,您就不需要使用拆解,并且修补的方法只会存在于范围内。

  • case-0-3.sql: 我在进行任何更改之前标记数据库: 之后,我在每个文件应用后应用文件和标记数据库: 求求你,救命。可能有人在sql或其他格式中使用回滚操作?哪里错了?我做错了什么?它是工作液基功能吗?