Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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__
BaseRequest.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.

like image 368
ThiefMaster Avatar asked Apr 23 '11 16:04

ThiefMaster


People also ask

What is read-only property in Python?

To define a readonly property, you need to create a property with only the getter. However, it is not truly read-only because you can always access the underlying attribute and change it. The read-only properties are useful in some cases such as for computed properties. This code works perfectly fine.

How do you make a Python property read-only?

If you need to make a read-only attribute in Python, you can turn your attribute into a property that delegates to an attribute with almost the same name, but with an underscore prefixed before the its name to note that it's private convention.

Which are read-only list which Cannot be modified in Python?

Tuples are, for most intents and purposes, 'immutable lists' - so by nature they will act as read-only objects that can't be directly set or modified.

How do you define a property in Python?

You can create a property by calling property() with an appropriate set of arguments and assigning its return value to a class attribute. All the arguments to property() are optional. However, you typically provide at least a setter function.


1 Answers

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
like image 153
samplebias Avatar answered Sep 21 '22 06:09

samplebias