From "outside", how can I access attributes in a property's getter function whether by unwrapping it or some other way?
In a python property, its __get__ function seems to be a wrapper of a wrapper of a wrapper ...
Using inspect.unwrap on the __get__ function returns another wrapper, not the getter. In fact, what unwrap returns seems to be the exact same object and id as what was unwrapped. See the MRE and its output below.
Yes, I know that in simple cases I can get the attribute through classinstance.__class__.propertygetterfunction._privateattribute
In my real situation, not the MRE below, the getter had been dynamically defined and is referenced only in synthesizing the property. Once created, there are no other references to the getter besides what is buried in the property.
What is the path from aclass.aproperty.__get__ to the getter and its attributes?
In the following MRE example, the getter contains one attribute containing how may times the getter has been called, and another containing the property's internal value.
from inspect import unwrap class propholder: def __init__(self): self.__class__.propgetter._usecount=0 def propgetter(self): self.__class__.propgetter._usecount=self.__class__.propgetter._usecount +1 print(f"getcount= {self.__class__.propgetter._usecount}") return self.__class__.propgetter._pvalue # set by the setter def propsetter(self, v): self.__class__.propgetter._pvalue=v # function to delete _age attribute def propdeleter(self): del self.__class__.propgetter del self.__class__.propsetter del self.__class__.propdeleter aprop = property(propgetter, propsetter, propdeleter) ap = propholder() for i in [10,11,12]: ap.aprop=i print(f" ap.aprop={ap.aprop} ") prop_get=ap.__class__.aprop.__get__ u=unwrap(prop_get) print( f"\n prop_get=ap.__class__.aprop.__get__ = {prop_get} of type {prop_get.__class__} at {id(prop_get)} ") print( f" u=unwrap(prop_get) = {u} of type {u} at {id(u)} ") un=u for i in range(2,6): u=unwrap(u) print( f" u=unwrap(u) = {u} of type {u} at {id(u)} ") Results:
getcount= 1 ap.aprop=10 getcount= 2 ap.aprop=11 getcount= 3 ap.aprop=12 prop_get=ap.__class__.aprop.__get__ = <method-wrapper '__get__' of property object at 0x72b6af94d940> of type <class 'method-wrapper'> at 126128955449232 u=unwrap(prop_get) = <method-wrapper '__get__' of property object at 0x72b6af94d940> of type <method-wrapper '__get__' of property object at 0x72b6af94d940> at 126128955449232 u=unwrap(u) = <method-wrapper '__get__' of property object at 0x72b6af94d940> of type <method-wrapper '__get__' of property object at 0x72b6af94d940> at 126128955449232 u=unwrap(u) = <method-wrapper '__get__' of property object at 0x72b6af94d940> of type <method-wrapper '__get__' of property object at 0x72b6af94d940> at 126128955449232 u=unwrap(u) = <method-wrapper '__get__' of property object at 0x72b6af94d940> of type <method-wrapper '__get__' of property object at 0x72b6af94d940> at 126128955449232 u=unwrap(u) = <method-wrapper '__get__' of property object at 0x72b6af94d940> of type <method-wrapper '__get__' of property object at 0x72b6af94d940> at 126128955449232
__get__seems like a recursive wrapper is that__get__itself is a function with a__get__method. (The descriptor how-to linked in my previous comment also discusses how instance methods are implemented via the descriptor protocol.)__get__'s__get__method is unrelated to the property's__get__method.