为什么property.fget是只读属性?
我现在正在修改一个库里类的属性,让它变得更灵活。
我用下面的代码来实现这个功能,效果很好:
_orig_is_xhr = BaseRequest.is_xhr.fget
_orig_is_xhr_doc = BaseRequest.is_xhr.__doc__
BaseRequest.is_xhr = property(lambda self: _orig_is_xhr(self) or
'_iframe-xhr' in request.form, doc=_orig_is_xhr_doc)
不过,如果我能直接重写获取这个属性的函数,那就更好了,这样文档说明也能保留下来:
_orig_is_xhr = BaseRequest.is_xhr.fget
BaseRequest.is_xhr.fget = lambda self: (_orig_is_xhr(self) or
'_iframe-xhr' in request.form)
但是这样做不行,因为 property.fget
是一个只读属性(尝试给它赋值时会报错:TypeError: readonly attribute
)。我很好奇这样设计是否有特别的原因,还是说 Python 的开发者觉得在创建属性后再去修改它没有意义,除非用一个新的属性来替换。
2 个回答
1
在IDLE环境中测试了Anaconda 2.3.0(Python 3.4.3)
>>> p = property()
>>> p.fget
>>> p.__init__( lambda obj: None )
>>> p.fget
<function <lambda> at 0x0121FF18>
>>> p.fget = lambda obj: None
Tracebabk (most recent call last):
File "<pyshell#19>", line 1, in <module>
p.fget = lambda obj: None
AttributeError: readonly attribute
>>>
在我看来,这看起来并不是只读的哦;)
6
你说得对,这些属性被设定为只读其实是一种约定,目的是让这个属性要么有值,要么没有值,不能部分有值。其实如果能在之后再给这些属性赋值,可能会更符合“Python风格”,但我在Python 2.2的发布说明中找不到相关的理由(那时候引入了属性这个概念)。
在Objects/descrobject.c文件中,这个属性的成员属性被定义为只读:
static PyMemberDef property_members[] = {
{"fget", T_OBJECT, offsetof(propertyobject, prop_get), READONLY},
{"fset", T_OBJECT, offsetof(propertyobject, prop_set), READONLY},
{"fdel", T_OBJECT, offsetof(propertyobject, prop_del), READONLY},
{"__doc__", T_OBJECT, offsetof(propertyobject, prop_doc), READONLY},
{0}
};
顺便说一下,如果你把READONLY
替换成0
并重新编译,就可以让fget, fset, ..
这些属性被赋值了:
class Test(object):
def __init__(self):
self.flag = True
prop = property(lambda self: self.flag)
obj = Test()
print obj.prop
Test.prop.fget = lambda self: not self.flag
print obj.prop
输出:
True
False