如何触发价值变化的功能?

Ben*_*min 48 python event-handling observer-pattern

我意识到这个问题与事件处理有关,我已经阅读了关于Python事件处理程序的调度程序,所以要么它没有回答我的问题,要么我完全错过了这些信息.

我想要在值发生变化时触发m()对象的方法:Av

例如(假设钱让人开心):

global_wealth = 0

class Person()
    def __init__(self):
        self.wealth = 0
        global global_wealth
        # here is where attribute should be
        # bound to changes in 'global_wealth'
        self.happiness = bind_to(global_wealth, how_happy)

    def how_happy(self, global_wealth):
        return self.wealth / global_wealth
Run Code Online (Sandbox Code Playgroud)

因此,每当global_wealth更改值时,类的所有实例Person都应相应地更改其happiness值.

注意:我必须编辑问题,因为第一个版本似乎暗示我需要getter和setter方法.对困惑感到抱歉.

Thi*_*ves 76

您需要使用观察者模式.在以下代码中,一个人订阅接收来自全球财富实体的更新.当全球财富发生变化时,该实体会向其所有订户(观察员)发出变更警报.然后人自我更新.

我在这个例子中使用了属性,但它们不是必需的.一个小警告:属性仅适用于新样式类,因此类声明之后的(对象)是必须的.

class GlobalWealth(object):
    def __init__(self):
        self._global_wealth = 10.0
        self._observers = []

    @property
    def global_wealth(self):
        return self._global_wealth

    @global_wealth.setter
    def global_wealth(self, value):
        self._global_wealth = value
        for callback in self._observers:
            print('announcing change')
            callback(self._global_wealth)

    def bind_to(self, callback):
        print('bound')
        self._observers.append(callback)


class Person(object):
    def __init__(self, data):
        self.wealth = 1.0
        self.data = data
        self.data.bind_to(self.update_how_happy)
        self.happiness = self.wealth / self.data.global_wealth

    def update_how_happy(self, global_wealth):
        self.happiness = self.wealth / global_wealth


if __name__ == '__main__':
    data = GlobalWealth()
    p = Person(data)
    print(p.happiness)
    data.global_wealth = 1.0
    print(p.happiness)
Run Code Online (Sandbox Code Playgroud)

  • 优秀:)我真的很喜欢你的榜样.我已经看到了观察者模式的记录,但没有看到它是我需要的答案.但有一件事:在你提出的代码的逻辑中,观察到的是"Global_Wealth",它是活跃的,而观察者"人"则是被动的.然而,在现实生活中,观察者是活跃的:观察者只是在改变自己,不会要求观察者改变.你明白我的意思吗?我只是为了在这里学习而质疑逻辑.但观察者活跃的代码能否正常运作? (3认同)
  • 请注意,此实现可能导致内存泄漏,因为`GlobalWealth`拥有对已注册回调的“强”引用,从而使Person对象保持活动状态。解决方案是使用[此答案](/sf/answers/1044549271/)中所述的弱引用。 (2认同)

Ros*_*ron 14

如果要在更改属性时执行代码,则可以使用属性.请注意,更改属性时出现的重大副作用或显着开销对于使用您的API的人来说有点令人惊讶,因此在某些情况下您可能希望通过使用方法来避免它.

class A(object):

    def m(self, p_value):
         print p_value

    @property
    def p(self):
        return self._p 

    @p.setter
    def p(self, value)
        self._p = value
        self.m(value)
Run Code Online (Sandbox Code Playgroud)

  • 我不认为这是我想要的,除非我误解了您的答案:为了清楚起见,我编辑了问题。 (2认同)
  • 已经有一段时间了,但是我不知道这个答案不能解决OP的问题。对我来说,这是一个很好的答案。 (2认同)

pet*_*hil 9

你在寻找什么称为(功能)反应式编程.对于Common Lisp,有Cell - 参见Cells项目Cells宣言,对于python,有Trellis库.

电子表格也使用相同的范例.对于跟踪多个相互关联的参数非常有用 - 例如在GUI编程中.

反应式编程类似于Observer模式,但有一个重要的区别:

与Observer模式的相似之处然而,将数据流概念集成到编程语言中会使表达它们变得更容易,因此可以增加数据流图的粒度.例如,观察者模式通常描述整个对象/类之间的数据流,而面向对象的反应式编程可以针对对象/类的成员.