【问题标题】:Callback on variable change in python回调python中的变量更改
【发布时间】:2018-08-16 20:59:01
【问题描述】:

我四处寻找,但没有找到类似的东西。假设我有一大群线程,它们不断读取和更新整数变量x。当x 变化超过一定的余量(比如说500)时,我想要一个回调来运行回调。

如何在不给系统带来沉重负担的情况下做到这一点,例如拥有一个具有while true 的线程并检查变量是否已更改?性能至关重要。但道德也是如此。

在纯代码中会是这样的:

x = 10
def runMe():
    print('Its greater than 500!!') 

def whenToRun():
    return x >= 500

triggers.event(runMe, whenToRun)

【问题讨论】:

  • x 必须是全局变量,还是可以是某个对象的属性?
  • 您可以将变量“隐藏”在负责通知观察者的设置器后面,或者(如果这根本不可行),您可以选择次优选项,即拥有一个线程不断检查变量中的值。
  • x 将是某个对象的属性
  • @AndrasDeak 好吧,你可以做到。一种方法是通过调试器挂钩,这可能太慢了。或者,您可以使用 __setitem__-hooked 容器作为模块 dict,以一种 hacky 方式,或者使用一个不错的导入钩子,为所有 .py 文件提供您的自定义 dict 子类。也许还有其他方式。

标签: python events concurrency


【解决方案1】:

你想要一个函数(一个“setter”),当变量的值改变时调用它。一个好的方法是定义一个@property。它的行为类似于一个变量,但会有一个 getter 函数和一个 setter 函数。

然后,在 setter 中,调用您需要的任何回调,这将对更改做出反应。

这应该可以解决问题:

class ObjectHoldingTheValue:
    def __init__(self, initial_value=0):
        self._value = initial_value
        self._callbacks = []

    @property
    def value(self):
        return self._value

    @value.setter
    def value(self, new_value):
        old_value = self._value
        self._value = new_value
        self._notify_observers(old_value, new_value)

    def _notify_observers(self, old_value, new_value):
        for callback in self._callbacks:
            callback(old_value, new_value)

    def register_callback(self, callback):
        self._callbacks.append(callback)

那么,你可以这样做:

def print_if_change_greater_than_500(old_value, new_value):
    if abs(old_value - new_value) > 500:
        print(f'The value changed by more than 500 (from {old_value} to {new_value})')

holder = ObjectHoldingTheValue()
holder.register_callback(print_if_change_greater_than_500)
holder.value = 7    # nothing is printed
holder.value = 70   # nothing is printed
holder.value = 700  # a message is printed

【讨论】:

  • 这解决了我在回调函数和框架方面遇到的类似问题......非常感谢,这应该被标记为解决方案。
  • 太棒了!正是我正在寻找适合我用例的那种模式,谢谢!!!
【解决方案2】:

如果x是某个对象的属性,而不是全局变量,这很简单:添加一个__setattr__方法:

class MyType:
    def __setattr__(self, name, value):
        if name == 'x':
            self.x_callback(value)
        super().__setattr__(name, value)

显然有一些方法可以让这更灵活:

  • 添加一种动态注册条件的方法,而不是总是调用x_callback
  • 使它成为一个可以附加到任何其他类的 mixin 类,让您register(name, callback) 随心所欲。
  • 结合以上,可以register(name, condition, callback)
  • self.x_callback(oldval=self.x, newval=value) 这样回调就可以看到新旧值。
  • if self.x_callback(value): 所以回调可以接受或拒绝更改。
  • value = self.x_callback(value) 所以回调可以覆盖更改。

【讨论】:

    猜你喜欢
    • 2021-12-15
    • 2017-03-16
    • 2015-06-25
    • 2017-05-16
    • 2016-11-15
    • 2021-10-02
    • 2013-03-25
    • 2019-01-29
    • 2016-09-29
    相关资源
    最近更新 更多