开发者

Why is property.fget a read-only attribute?

I'm currently patching a property of a class from a library to make it more versatile.

I'm doing this using the following code which works fine:

_orig_is_xhr = BaseRequest.is_xhr.fget
_orig_is_xhr_doc = BaseRequest.is_xhr.__doc__
Bas开发者_Go百科eRequest.is_xhr = property(lambda self: _orig_is_xhr(self) or
    '_iframe-xhr' in request.form, doc=_orig_is_xhr_doc)

However, it would be much nicer if i could simply overwrite the getter function so the docstring is preserved:

_orig_is_xhr = BaseRequest.is_xhr.fget
BaseRequest.is_xhr.fget = lambda self: (_orig_is_xhr(self) or
    '_iframe-xhr' in request.form)

This doesn't work because property.fget is a read-only attribute (TypeError: readonly attribute when trying to assign to it). I'm curious if there is a special reason for this or it the python developers just thought it makes no sense to modify a property after creating it without replacing it with a new one.


You're probably right, that it's just a convention to make those attributes read-only, chosen to make the property "all-or-nothing". Seems it'd be a bit more "Pythonic" to allow these to be assigned after the fact, but can't find the rationale in the Python 2.2 release notes (when properties were introduced).

In Objects/descrobject.c the property's member attributes are defined as read-only:

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

Aside: if you replace READONLY with 0 and compile, that's all it takes to allow fget, fset, .. to be assigned:

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

Output:

True
False


tested with Anaconda 2.3.0 (Python 3.4.3) in an IDLE shell

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

doesn't look so readonly to me ;)

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜