Python - 从动态attrname列表中创建__init__中的属性

时间:2012-11-09 15:16:35

标签: python plugins properties constructor

我正在为一些天文馆软件编写Python插件。这个插件附带了访问天文馆软件命名空间内对象的功能,但它们很麻烦而且不是OOP。因此,我试图创建一个类,该类将重载属性访问以简化编码。我希望能够做到这样的事情,

rocket = RemoteObject('rocket')
rocket.color = blue

将天文馆软件命名空间中火箭对象的颜色设置为蓝色。

How to define properties in __init__非常接近。我遇到的一个难点是,我需要在创建实例时确定属性的名称。另一个困难是由于我对描述符的理解很差:属性调用正在返回或覆盖我的属性对象本身而不是调用它的getter和setter。

这是我到目前为止所做的:

class RemoteObject(object):
    def __init__(self,remote_object_name):
        self.normalattr = 'foo'
        self.normalmethod = lambda: 'spam'
        for attrname in get_remote_object_attrnames(remote_object_name):
            def _get(self):
                return fetch_remote_attr_value(remote_object_name,attrname)
            def _set(self,value):
                set_remote_attr_value(remote_object_name,attrname,value)
            setattr(self,attrname,property(_get,_set))

if __name__ == '__main__':
    get_remote_object_attrnames = lambda name: {'apple','banana','cherry'}
    fetch_remote_attr_value = lambda o,a: 'Reading %s.%s' % (o,a)
    set_remote_attr_value = lambda o,a,v: 'Writing %s.%s = %s' % (o,a,v)

    scene = RemoteObject('scene')
    for x in scene.__dict__.items(): print x
    print '-----'
    print scene.normalattr
    print scene.normalmethod()
    print scene.apple
    scene.banana = '42'
    print '-----'
    for x in scene.__dict__.items(): print x

运行时,它会返回:

('cherry', <property object at 0x00CB65A0>)
('normalmethod', <function <lambda> at 0x00CB8FB0>)
('banana', <property object at 0x00CB65D0>)
('normalattr', 'foo')
('apple', <property object at 0x00CB6600>)
-----
foo
spam
<property object at 0x00CB6600>
-----
('cherry', <property object at 0x00CB65A0>)
('normalmethod', <function <lambda> at 0x00CB8FB0>)
('banana', '42')
('normalattr', 'foo')
('apple', <property object at 0x00CB6600>)

有没有更好的方法来处理每个实例需要属性的动态attrnset集?为什么实例属性匹配返回属性对象本身的属性名称而不是执行其getter或setter?

2 个答案:

答案 0 :(得分:4)

您无法在实例上定义属性; property个对象是描述符,只有类支持描述符__get____set__挂钩。

您必须在类上定义所有这些属性并禁用它们(可能从已禁用的属性中抛出AttributeError),或使用__getattr__和{ {1}}而不是。

'全部定义'方法:

__setattr__

class Foo(object): __enabled_properties = () def __init__(self): self.__enabled_properties = ('bar',) @property def bar(self): if 'bar' not in self.__enabled_properties: raise AttributeError('bar') ... @bar.setter def bar(self, value): if 'bar' not in self.__enabled_properties: raise AttributeError('bar') ... __getattr__方法:

__setattr__

答案 1 :(得分:0)

您可以更轻松地使用namedtuple。这是另一个回答相似的问题:How to add property to a class dynamically?