动态向类添加属性
这个问题之前在Stack Overflow上也有人问过,但似乎没有一个答案能完全解决我想做的事情。在我的情况下,我希望这些动态添加的属性能够作为一个快捷方式,用来从数据库中存储和读取值,所以这并不像这个答案(使用了lambda
函数)或这个答案(把值存储在字典里)那么简单:我必须调用类的其他方法。
这是我的尝试:
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 个回答
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')
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
如果这对你有帮助,请确认这是答案。谢谢!