2

This has been previously asked on Stack Overflow, but none of the answers seem to address exactly what I need to do. In my case, I want these dynamically-added properties to be a shortcut to store and read values from a database, so unfortunately it's not as easy as in this answer (where a lambda function was used) or this one (where values where stored in a dictionary): I must call other methods of the class.

This is my attempt:

import operator class Foo(object): def get_value(self, name): # read and return value from database return -1 def set_value(self, name, value): # store value in database pass def add_metadata_property(name): getter = operator.methodcaller('get_value', name) setter = operator.methodcaller('set_value', name) # gets value at runtime setattr(Foo, name, property(getter, setter)) add_metadata_property('spam') f = Foo() f.spam # works! f.spam = 2 

The last line, however, raises:

Traceback (most recent call last): File "<stdin>", line 27, in <module> TypeError: methodcaller expected 1 arguments, got 2 

Any ideas on how to achieve this?

2
  • 2
    Have you tried using the lambda answer, providing function objects instead of lambdas? Commented Jul 1, 2014 at 12:15
  • 1
    You might be interested in this answer stackoverflow.com/questions/1224962/… Commented Jul 1, 2014 at 12:37

2 Answers 2

4

I don't know why you use operator.methodcaller here. When you call f.spam=2, it will invoke setter. setter = operator.methodcaller('set_value', name) means setter(r) = r.set_value(name). Make no sense in your case.

I suggest you write this way, using @classmethod:

class Foo(object): @classmethod def get_value(self, name): # read and return value from database return -1 @classmethod def set_value(self, name, value): # store value in database pass def add_metadata_property(name): setattr(Foo, name, property(Foo.get_value, Foo.set_value)) add_metadata_property('spam') f = Foo() f.spam # works! f.spam = 2 

If this helped you, please confirm it as the answer. Thanks!

Sign up to request clarification or add additional context in comments.

Comments

1

Modifying class template looks a bit odd for me. I would suggest to overload __getattr__() and __setattr__() methods in your case.

class Foo: def __getattr__(self, name): print('read and return value from database for ', name) return 123 def __setattr__(self, name, value): print('store value', value, 'for', name, 'in database') 

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.