如何动态添加属性到python类?

问题:

目标是创建一个类似于db结果集的模拟类。
所以例如,如果数据库查询返回,使用dict表达式{'ab':100, 'cd':200},那么我想看看:

>>> dummy.ab
100

起初我以为也许我可以这样做:

ks = ['ab', 'cd']
vs = [12, 34]
class C(dict):
    def __init__(self, ks, vs):
        for i, k in enumerate(ks):
            self[k] = vs[i]
            setattr(self, k, property(lambda x: vs[i], self.fn_readyonly))

    def fn_readonly(self, v)
        raise "It is ready only"

if __name__ == "__main__":
    c = C(ks, vs)
    print c.ab

c.ab则返回属性对象。
使用k = property(lambda x: vs[i])替换setattr行完全没有用。
那么在运行时创建实例属性的正确方法是什么?
附:我知道在How is the __getattribute__ method used?中提出的替代方案

回答:

我想我应该扩大这个答案,现在我更年长了,知道发生了什么。迟到总比不到好。
can动态添加一个属性到一个类。但这是抓住:您必须将其添加到class

>>> class Foo(object):
...     pass
... 
>>> foo = Foo()
>>> foo.a = 3
>>> Foo.b = property(lambda self: self.a + 1)
>>> foo.b
4

一个property实际上是一个称为descriptor的东西的简单实现。这是一个给定属性on a given class的自定义处理的对象。金达喜欢像__getattribute__的一个巨大的if树,
当我在上面的例子中要求foo.b时,Python看到在类上定义的b实现了descriptor protocol,这只意味着它是一个具有__get____set____delete__方法的对象。描述符声称负责处理该属性,所以Python调用Foo.b.__get__(foo, Foo),返回值作为属性的值传回给你。在property的情况下,这些方法中的每一个只调用fgetfsetfdel传递给property构造函数。
描述符确实是Python暴露其整个OO实现的管道的方式。实际上,还有另一种类型的描述符比property更常见

>>> class Foo(object):
...     def bar(self):
...         pass
... 
>>> Foo().bar
<bound method Foo.bar of <__main__.Foo object at 0x7f2a439d5dd0>>
>>> Foo().bar.__get__
<method-wrapper '__get__' of instancemethod object at 0x7f2a43a8a5a0>

谦卑的方法只是另一种描述符。调用实例中的__get__插入作为第一个参数;实际上它是这样做的:

def __get__(self, instance, owner):
    return functools.partial(self.function, instance)

无论如何,我怀疑这是为什么描述符只能在课堂上工作:他们是一个正式化的东西,强制课程的首先。他们甚至是规则的例外:您可以明确地将描述符分配给一个类,并且类本身是type的实例!实际上,试图读取Foo.b仍然称为property.__get__;描述符在访问时作为类属性返回自身只是惯用的。
我认为,Python的所有OO系统都可以用Python表达,这很酷。 🙂
哦,如果你有兴趣,我写了wordy blog post about descriptors一段时间。

 
 
Code问答: http://codewenda.com/topics/python/
Stackoverflow: How to add property to a python class dynamically?

*转载请注明本文链接以及stackoverflow的英文链接

发表评论

电子邮件地址不会被公开。 必填项已用*标注

54 + = 55