Multiple properties with similar getter/setter functions?

坚强是说给别人听的谎言 提交于 2020-12-26 05:09:06

问题


What is the cleanest way to define a class with a large number of properties, each of which calls the same setter function with a different parameter?

Below is what I'm trying to achieve. Each of the three properties (red_LED etc) call the same TalkToHardware() function when they are set, but with a different address. As you can see, this works, but the class definition is long and unwieldy. It is also error prone.

class Hardware_Controller(object):

    def __init__(self):
        self.red_LED_address = 0
        self.blue_LED_address = 1
        self.green_LED_address = 2

    @property
    def red_LED(self):
        return self._red_LED_status

    @red_LED.setter
    def red_LED(self,value):
        self.TalkToHardware(self.red_LED_address,value)
        self._red_LED_status = value

    @property
    def blue_LED(self):
        return self._red_LED_status

    @blue_LED.setter
    def blue_LED(self,value):
        self.TalkToHardware(self.blue_LED_address,value)
        self._blue_LED_status = value

    @property
    def green_LED(self):
        return self._red_LED_status

    @green_LED.setter
    def green_LED(self,value):
        self.TalkToHardware(self.green_LED_address,value)
        self._green_LED_status = value

    def TalkToHardware(self,address,value):
        print('Sending %i to address %i' % (value,address))

if __name__ == "__main__":
    a = Hardware_Controller()
    a.red_LED = 1
    a.green_LED = 0
    print(a.red_LED)

Output:

Sending 1 to address 0
Sending 0 to address 2
1

I would like the class definition to look more like this:

class Hardware_Controller(object):

    def __init__(self):
        self.red_LED_address = 0
        self.blue_LED_address = 1
        self.green_LED_address = 2

        self.red_LED = some_magic(self.red_LED_address)
        self.blue_LED = some_magic(self.blue_LED_address)
        self.green_LED = some_magic(self.green_LED_address)

    def some_magic(address):
        # Do magic things
        pass

Is there a clean way to accomplish this, still being able to access each of the LEDs directly as shown in the main function of the first example?


回答1:


You could create a function that simply defines and returns the needed property class instance and then use it to define the class, thus getting rid of all that repetitive code .

(In case it's not obvious, the LED_property() function in the code below corresponds to the one named some_magic() in your question.)

class Hardware_Controller(object):
    def LED_property(color_name):
        """ Create and return a property for the given color_name. """
        address_name = color_name + '_LED_address'
        storage_name = '_' + color_name + '_LED_status'

        @property
        def prop(self):
            return getattr(self, storage_name)

        @prop.setter
        def prop(self, value):
            address = getattr(self, address_name)
            self.TalkToHardware(address, value)
            setattr(self, storage_name, value)

        return prop

    red_LED = LED_property('red')
    blue_LED = LED_property('blue')
    green_LED = LED_property('green')

    def __init__(self):
        self.red_LED_address = 0
        self.blue_LED_address = 1
        self.green_LED_address = 2

    def TalkToHardware(self, address, value):
        print('Sending %i to address %i' % (value, address))

    del LED_property  # Function isn't needed outside class definition.


if __name__ == "__main__":
    a = Hardware_Controller()
    a.red_LED = 1     # -> Sending 1 to address 0
    a.green_LED = 0   # -> Sending 0 to address 2
    print(a.red_LED)  # -> 1

Similar to recipe "9.21 Avoiding Repetitive Property Methods" in the Python Cookbook, Third Edition by David Beazley & Brian Jones (2013). I found a PDF of the entire book (8.8 Mb), the recipe's on page 382.




回答2:


Perhaps you can do this:

def setter(self, address, value):
    if address == self.red_LED_address:
        attr = '_red_LED_status'
    if address == self.blue_LED_address:
        attr = '_blue_LED_status'
    if address == self.green_LED_address:
        attr = '_green_LED_status'
    self.TalkToHardware(address, value)
    setattr(self, attr, value) ## does this: self._XXX_LED_address = value

This is a catch-all function for all of your LED setter functions.

I hope this was helpful!



来源:https://stackoverflow.com/questions/49888437/multiple-properties-with-similar-getter-setter-functions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!