1

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

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

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

如何定义属性__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>)

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

4

2 回答 2

5

您不能在实例上定义属性;对象是描述符,只有类支持property描述符__get__和挂钩。__set__

您必须在类上定义所有这些属性并禁用AttributeError它们(可能从禁用的属性中抛出),或者使用__getattr__and__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__

class Foo(object):
    __enabled_properties = ()
    __dynamic_properties = ('bar', 'spam', 'eggs')

    def __init__(self):
        self.__enabled_properties = ('bar',)

    def __getattr__(self, attr):
        if attr in self.__dynamic_properties:
            if attr not in self.__enabled_properties:
                raise AttributeError(attr)
            # Fetch a remote value here and return it
        if attr not in self.__dict__:
            raise AttributeError(attr)
        return self.__dict__[attr]

    def __setattr__(self, attr, value):
        if attr in self.__dynamic_properties:
            if attr not in self.__enabled_properties:
                raise AttributeError(attr)
            # Set a remote value here
        self.__dict__[attr] = value
于 2012-11-09T15:20:50.090 回答
0

您可能会更轻松地使用namedtuple. 这是另一个具有类似答案的问题:如何动态地将属性添加到类中?

于 2012-11-09T15:23:25.757 回答