动态地向类添加属性

时间:2014-07-01 11:58:42

标签: python properties

之前已经在Stack Overflow上提出过这个问题,但是没有一个答案似乎能解决我需要做的事情。在我的情况下,我希望这些动态添加的属性是存储和读取数据库中的值的快捷方式,所以不幸的是它不是那么容易as in this answer(其中使用了lambda函数)或this one(其中存储在字典中的值):我必须调用该类的其他方法。

这是我的尝试:

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

然而,最后一行提出:

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

关于如何实现这一目标的任何想法?

2 个答案:

答案 0 :(得分:4)

我不知道你在这里使用operator.methodcaller的原因。 当你致电f.spam=2时,它会调用setter。 setter = operator.methodcaller('set_value', name)表示setter(r) = r.set_value(name)。在你的情况下毫无意义。

我建议你这样写,使用@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

如果这对您有帮助,请确认答案。谢谢!

答案 1 :(得分:1)

修改类模板对我来说有点奇怪。我建议您在案例中重载__getattr__()__setattr__()方法。

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')