2011-04-23 96 views
6

我目前正在从库中修补一个类的属性,以使其更通用。为什么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) 

然而,这将是更漂亮,如果我可以简单地覆盖getter函数使文档字符串被保留:

_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开发人员只是认为它没有任何意义的修改后创建一个属性,而不用一个新的替换它。

回答

6

你可能是对的,它只是一个约定,使这些属性为只读,选择使属性“全有或全无”。似乎它会多一点“Pythonic”,以允许这些事后分配,但无法找到Python 2.2 release notes(当属性被引入)的基本原理。

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} 
    }; 

旁白:如果更换READONLY0和编译,这一切都需要允许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 
+0

嘿,不错 - 我不会破解蟒蛇来源虽然:p – ThiefMaster 2011-04-23 18:56:12

+2

当然:-)我只是指出,只读的背后没有什么更奇特的东西。 – samplebias 2011-04-23 18:58:44

+1

可变属性会为无意的副作用创造一些可怕的机会。 'Thread.ident.fget = Thread.daemon.fget'任何人? – ncoghlan 2011-04-24 17:10:00

0

与蟒蛇2.3.0(Python的3.4.3)在IDLE壳测试

>>> 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 
>>> 

看起来不那么只读给我;)