2

In a class, I want to define N persistent properties. I can implement them as follow:

@property
def prop1(self):
    return self.__prop1
@prop1.setter
def prop1(self, value):
    self.__prop1 = value
    persistenceManagement()        

@property
def prop2(self):
    return self.__prop2
@prop2.setter
def prop2(self, value):
    self.__prop2 = value
    persistenceManagement()       

[...]

@property
def propN(self):
    return self.__propN
@propN.setter
def propN(self, value):
    self.__propN = value
    persistenceManagement()       

Of course, the only different thing between these blocks is the property name (prop1, prop2, ..., propN). persistenceManagement() is a function that has to be called when the value of one of these property changes.

Since these blocks of code are identical except for a single information (i.e., the property name), I suppose there must be some way to replace each of these blocks by single lines declaring the existence of a persistent property with a given name. Something like

def someMagicalPatternFunction(...):
     [...]


someMagicalPatternFunction("prop1")
someMagicalPatternFunction("prop2")
[...]
someMagicalPatternFunction("propN")

...or maybe some decorating trick that I cannot see at the moment. Is someone has an idea how this could be done?

Christian O'Reilly
  • 1,864
  • 3
  • 18
  • 33

2 Answers2

3

Properties are just descriptor classes and you can create your own and use them:

class MyDescriptor(object):
    def __init__(self, name, func):
        self.func = func
        self.attr_name = '__' + name
    def __get__(self, instance, owner):
        return getattr(self, self.attr_name)
    def __set__(self, instance, value):
        setattr(self, self.attr_name, value)
        self.func(self.attr_name)

def postprocess(attr_name):
    print 'postprocess called after setting', attr_name

class Example(object):
    prop1 = MyDescriptor('prop1', postprocess)
    prop2 = MyDescriptor('prop2', postprocess)

obj = Example()
obj.prop1 = 'answer'  # prints 'postprocess called after setting __prop1'
obj.prop2 = 42  # prints 'postprocess called after setting __prop2'

Optionally you can make it a little easier to use with something like this:

def my_property(name, postprocess=postprocess):
    return MyDescriptor(name, postprocess)

class Example(object):
    prop1 = my_property('prop1')
    prop2 = my_property('prop2')

If you like the decorator @ syntax, you could do it this way (which also alleviates having to type the name of the property twice) -- however the dummy functions it requires seem a little weird...

def my_property(method):
    name = method.__name__
    return MyDescriptor(name, postprocess)

class Example(object):
    @my_property
    def prop1(self): pass
    @my_property
    def prop2(self): pass
martineau
  • 119,623
  • 25
  • 170
  • 301
1

The property class (yes it's a class) is just one possible implementation of the descriptor protocol (which is fully documented here: http://docs.python.org/2/howto/descriptor.html). Just write your own custom descriptor and you'll be done.

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118