Why is the .fget property of a read-only attribute?

I am currently fixing a class property from a library to make it more universal.

I do this using the following code that 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 better if I could just overwrite the getter function to save the docstring:

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

This does not work because property.fget is a read-only attribute ( TypeError: readonly attribute when trying to assign to it). I am curious if there is a special reason for this, or the python developers just thought that it makes no sense to modify the property after it was created without replacing it with a new one.

+6
source share
2 answers

You are probably right that it is simply an agreement to make these read-only attributes selected in order to make the all or nothing property. It looks like it will be a bit more โ€œPythonicโ€ to allow them to be assigned after the fact, but cannot find the rationale in the Python 2.2 release notes (when the properties were introduced).

In Objects / descrobject.c, the attributes of a property element 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} }; 

Also: if you replace READONLY with 0 and compile, all it takes to assign 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 

Conclusion:

 True False 
+6
source

tested with Anaconda 2.3.0 (Python 3.4.3) in 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 like read-only to me;)

0
source

Source: https://habr.com/ru/post/886542/


All Articles