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?

3
  • So what you're trying to do is just have a function run after any of those properties is set, right? Commented Oct 16, 2013 at 16:48
  • @Blender Well... to get the setter and getter automatically declared + adding one line of code to the setter for the persistency. Commented Oct 16, 2013 at 16:51
  • @martineau I blame the copy&paste. Thanks for noticing. I've edited the question. Commented Oct 16, 2013 at 17:03

2 Answers 2

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
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. Very enlightening.
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.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.