如何覆盖类似dict的对象的属性设置?

时间:2011-02-28 18:45:08

标签: python

我正在编写一个C绑定,而我正在包装的C结构有一些字符串索引的属性值。

我想在python中将这些作为dict公开。

到目前为止,我有一个函数get_properties,它将所有对象的属性作为单个dict返回。我使用类定义中的property函数将其包装,以便我可以作为类属性访问它:

(在课堂定义中)

class MyClass:
    def get_properties(self):
        ...
    properties = property(get_properties)

(实施例)

>>> print myobj.properties
{'test': 5, 'test2': 'string'}

现在,我想以类似dict的方式设置它们。我有一个名为set_property的C函数的包装函数,它接受一个字符串键和几种类型的值。

我尝试使用我的班级set_properties中的property

class MyClass:
    def get_properties(self):
        ...
    def set_property(self, key, value):
        ...
    def set_properties(self, props):
        [self.set_property(k, props[k]) for k in props]
    properties = property(get_properties, set_properties)

这样做如下:

>>> myobj.properties = {"test3": 6}
>>> print myobj.properties
{'test': 5, 'test2': 'string', 'test3': 6}

但是,正如您所看到的那样,并不完全是预期的行为。我更喜欢的是:

>>> myobj.properties['test3'] = 6

我尝试将__setitem__的定义添加到properties

class MyClass:
    ...
    properties = property(get_properties)
    properties.__setitem__ = set_property

但这让我了,

AttributeError: 'property' object has no attribute '__setitem__'

我尝试将属性设为dict,只是覆盖__setitem____getitem__,但它不会拥有它。

知道正确的方法是什么?我可以让班级property表现得像字典吗?

感谢。

2 个答案:

答案 0 :(得分:2)

好的,Mike的回答给了我一个想法,通过从属性的getter返回一个扩展的dict类来解决这个问题,我在其中根据上下文覆盖__setitem__

class MyClass(object):
    def get_properties():
        ... (call C function and convert to dict)
    def set_property():
        ... (call C function)
    def propgetter(self):
        context = self
        props = self.get_properties()
        class propsetter(dict):
            __getitem__ = props.__getitem__
            def __setitem__(self, key, value):
                props[key] = value
                context.set_property(key, value)
        return propsetter(self.get_properties())
    properties = property(propgetter)

似乎按我的意愿工作。

答案 1 :(得分:1)

您定义属性的方式是只读的。但是,属性装饰器实际上可以选择设置和获取函数:

class MyClass(object):
    def __init__(self):
        self.d = {"hello":None}
    def __repr__(self):
        return "%s"%(self.d,)
    def get(self):
        return self.d
    def set(self, value):
        self.d = value
    x = property(get, set)

通过为内部词典定义一个setter,您现在可以在其上设置键:

>>> c = MyClass()
>>> c.x
{'hello': None}
>>> c.x["hello"] = "world"
>>> c.x
{'hello': 'world'}
>>> c.x = {"key":"value"}
>>> c.x
{'key': 'value'}

此外,如果您使用的是更新版本的Python(2.6+),您可以使用这样的装饰器编写更好的方法:

class MyClass():
    def __init__(self):
        self.d = {"hello":None}
    def __repr__(self):
        return "%s"%(self.d,)
    @property
    def x(self):
        return self.d
    @x.setter
    def set(self, value):
        self.d = value