简体   繁体   English

如何使用属性设置器作为回调

[英]How to use property setter as a callback

I'm working with a legacy system for which a Python interface has been added recently.我正在使用一个遗留系统,最近为其添加了 Python 接口。 In my code, I get messages containing ASCII strings for attributes to be set in some wrapper classes.在我的代码中,我收到包含要在某些包装类中设置的属性的 ASCII 字符串的消息。 I would like to use a dictionary to map "data labels" to property setter methods.我想使用字典来 map “数据标签”到属性设置器方法。 Each property setter would be used as a "callback" when the corresponding data label is encountered in a message.当在消息中遇到相应的数据 label 时,每个属性设置器都将用作“回调”。

Using explicit setters/getters, the essential logic looks like this:使用显式设置器/获取器,基本逻辑如下所示:

class A():
    def __init__(self):
        self._x = 1.2

    def get_x(self):
        return self._x

    def set_x(self, value):
        self._x = value

myA = A()

myTable = {
    'X' : myA.set_x,
}

label, value = get_message()

print(myA.get_x())
# label is 'X', value a float
myTable[label](value)
print(myA.get_x())

This works, but is a bit ugly.这有效,但有点难看。 I would like to use the @property decorator, but then I don't know how to reference the setter method in the dictionary.我想使用@property装饰器,但是我不知道如何在字典中引用setter 方法。 Ie the following doesn't work.即以下不起作用。

class B():
    def __init__(self):
        self._x = 1.2

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, value):
        self._x = value

myB = B()

myTable = {
    'X' : myB.x
}

label, value = get_message()

print(myB.x)
# doesn't work as expected
myTable[label] = value
# no change
print(myB.x)

Of course, the reference to property myB.x in the dictionary definition calls the getter, so a float value is associated to the 'X' key.当然,字典定义中对属性myB.x的引用调用了 getter,因此浮点值与“X”键相关联。 The myTable[label] = value assignment just replaces this value, it doesn't call the setter. myTable[label] = value赋值只是替换这个值,它不调用 setter。

So, is there a way to get a reference to the property setter to insert in the dictionary and to later invoke as a "callback"?那么,有没有办法获得对属性设置器的引用以插入字典并稍后作为“回调”调用?

I dug in reference information and this answer , but can't figure out a solution by myself.我挖掘了参考信息和这个答案,但自己无法找到解决方案。

Or, am I getting it wrong and I should follow a different path?或者,我是不是弄错了,我应该走另一条路? (Suggestions welcome). (欢迎提出建议)。

To access the actual function, you have to access the property directly on the class, so: 要访问实际函数,您必须直接在类上访问属性,因此:

In [1]: class B:
   ...:     def __init__(self):
   ...:         self._x = 1.2
   ...:
   ...:     @property
   ...:     def x(self):
   ...:         return self._x
   ...:
   ...:     @x.setter
   ...:     def x(self, value):
   ...:         self._x = value
   ...:

In [2]: B.x.fset
Out[2]: <function __main__.B.x(self, value)>

Since functions are descriptors, you can use their __get__ method to bind them and change them into a method: 由于函数是描述符,您可以使用它们的__get__方法绑定它们并将它们更改为方法:

In [4]: B.x.fset.__get__(b)(42)

In [5]: b.x
Out[5]: 42

So, something like: 所以,像:

In [6]: my_table = {'X':B.x.fset.__get__(b)}

In [7]: my_table['X']('foo')

In [8]: b.x
Out[8]: 'foo'

I'm coming to this several years late, but I have a similar situation, and building off of juanpa.arrivillaga's answer I came up with this to answer your follow-up question, which is maybe what you were really hoping for originally.我来晚了几年,但我有类似的情况,并且基于 juanpa.arrivillaga 的回答,我想出了这个来回答你的后续问题,这可能是你最初真正希望的。

Basically, an instance of TestDevice can use its own class method and getattr to find and call the appropriate setter:基本上,TestDevice 的一个实例可以使用它自己的 class 方法和 getattr 来查找和调用适当的设置器:

class TestDevice(object):

    @classmethod
    def set_property(cls, instance, property, value):
        getattr(cls, property).fset(instance, value)

    def __init__(self, x):
        self.x = x

    def apply_state(self, state):
        for k, v in state.items():
            self.set_property(self, k, v)

    @property
    def x(self):
        return self._x

    @x.setter
    def x(self, v):
        self._x = v

Which seems to do the trick:这似乎可以解决问题:

>>> thing = TestDevice(5)
>>> thing.x
5
>>> new_state = {'x': 7}
>>> thing.apply_state(new_state)
>>> thing.x
7

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM