我如何从导入的 class 'listen' to/decorate 一个 setter

How would I 'listen' to/decorate a setter from an imported class

我不确定这是否是一个很好的使用方法,但我对 Python 的经验并不丰富,所以请接受我的歉意。我已经尝试对此进行一些研究,但其他相关问题已经给出了针对特定问题的替代解决方案 - none 其中适用于我的具体案例。

我有一个 class 来处理我的特定机器学习模型的 training/querying。该算法在远程传感器上 运行,如果未训练算法,则将各种值输入 returns None 的对象。训练完成后,它 returns TrueFalse 取决于分配给新输入的 classification。有时,class 会更新几个阈值参数,我需要知道何时会发生这种情况。

我正在使用套接字将消息从远程传感器传递到我的主服务器。我不想通过用消息传递代码填充它来使 ML 算法 class 复杂化,因此我一直在导入“算法”的 Main class 中处理它class。我希望 Main class 能够确定何时更新阈值参数并将其报告回服务器。

class MyAlgorithmClass:

    def feed_value(self):
         ....


class Main:

    def __init__(self):
        self._algorithm_data = MyAlgorithmClass()
        self._sensor_data_queue = Queue()

    def process_data(self):
        while True:
            sensor_value = self._sensor_data_queue.get()
            result, value = self._algorithm_data.feed_value(sensor_value)
            if result is None:
                # value represents % training complete
                self._socket.emit('training', value)
            elif result is True:
                # value represents % chance that input is categoryA
                self._socket.emit('categoryA', value)
            elif result is False:
                ...

我最初的想法是用 setter 在 MyAlgorithmClass 中添加一个 属性。然后我可以在我的 Main class 中装饰它,这样每次调用 setter 时,我都可以使用该值...例如:

class MyAlgorithmClass:
    
    @property
    def param1(self):
        return self._param1

    @param1.setter
    def param1(self, value):
        self._param1 = value


class Main:

    def __init__(self):
        self._algorithm_data = MyAlgorithmClass()
        self._sensor_data_queue = Queue()    

        def watch_param1(func):
            def inner(*args):
                self._socket.emit('param1_updated', *args)
            func(*args)

我现在的问题是,如何用 watch_param1 装饰 self._algorithm_data.param1 setter?如果我简单地设置 self._algorithm_data.param1 = watch_param1 那么我将最终设置 self._algorithm_data._param1 等于我的函数,这不是我想要做的。

我可以使用 getter/setter 方法而不是 属性,但这不是很 pythonic,并且由于多人正在修改此代码,我不希望这些方法是 replaced/changed 稍后由其他人提供属性。

最好的方法是什么?这是一个小例子,但我稍后会有稍微复杂的例子,我不想要导致算法过于复杂的东西 class。显然,另一种选择是观察者模式,但我不确定在某些情况下我只有一个变量要监视的情况下它在这里有多合适。

我真的很难找到一个好的解决方案,所以任何建议都将不胜感激。

提前致谢,

汤姆

在Python中使用descriptors. They let you customize attribute lookup, storage, and deletion

带有描述符的代码的简化玩具版本类似于:

class WatchedParam:
    def __init__(self, name):
        self.name = name
        
    def __get__(self, instance, insttype=None):
        print(f"{self.name} : value accessed")
        return getattr(instance, '_' + self.name)
    
    def __set__(self, instance, new_val):
        print(f"{self.name} : value set")
        setattr(instance, '_' + self.name, new_val)

class MyAlgorithmClass:
    param1 = WatchedParam("param1")
    param2 = WatchedParam("param2")

    def __init__(self, param1, param2, param3):
        self.param1 = param1
        self.param2 = param2
        self.param3 = param3

class Main:
    def __init__(self):
        self._data = MyAlgorithmClass(10, 20, 50)

m = Main()
m._data.param1 # calls WatchedParam.__get__
m._data.param2 = 100 # calls WatchedParam.__set__

WatchedParamclass是一个描述符,可以在MyAlgorithmClass中用来指定需要监控的参数。

我寻求的解决方案如下,使用覆盖属性的 'Proxy' subclass。最终,一旦我对监视的参数有了更好的理解,我就不需要再监视它们了。在这一点上,我将能够换出基础 class 的代理并继续正常使用代码。

class MyAlgorithmClassProxy(MyAlgorithmClass):

    @property
    def watch_param1(self):
        return MyAlgorithmClass.watch_param1.fget(self)

    @watch_param1.setter
    def watch_param1(self, value):
        self._socket.emit('param1_updated', *args)
        MyAlgorithmClass.watch_param1.fset(self, value)