【问题标题】:How would I 'listen' to/decorate a setter from an imported class我将如何“听”/装饰导入类中的设置器
【发布时间】:2020-11-06 16:33:43
【问题描述】:

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

我有一个类可以处理我的特定机器学习模型的训练/查询。该算法在远程传感器上运行,如果算法未经过训练,则将各种值输入对象返回None。训练后,它会根据分配给新输入的分类返回TrueFalse。有时,该类会更新几个阈值参数,我需要知道何时发生这种情况。

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

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 类中装饰它,以便每次调用 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,并且由于多人正在修改此代码,我不希望稍后其他人为属性替换/更改这些方法.

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

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

提前致谢,

汤姆

【问题讨论】:

    标签: python python-3.x properties observer-pattern python-socketio


    【解决方案1】:

    使用descriptors。他们让你在 Python 中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__
    

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

    【讨论】:

      【解决方案2】:

      我采用的解决方案如下,使用覆盖属性的“代理”子类。最终,一旦我对观察的参数有了更好的理解,我就不再需要观察它们了。此时,我将能够将 Proxy 换成基类并继续正常使用代码。

      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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-06-20
        • 2011-07-17
        • 2019-02-11
        • 2016-02-21
        • 2023-04-04
        • 2019-03-25
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多