Perhaps I am rewording an above answer, but this presentation of the thoughts above seemed easier to follow for me.
Consider this implementation of @cached_property
class cached_property(object):
"""Like @property, but caches the value."""
def __init__(self, func):
self._func = func
def __get__(self, obj, cls):
if obj is None:
return self
value = self._func(obj)
obj.__dict__[self.__name__] = value
return value
I had the same question regarding "Why is obj checked for None?" and "Why return self?"
Here's an example of how both of the situations arise
The typical usage:
class Foo(object):
@cached_property
def foo(self):
# Would usually have significant computation here
return 9001
foo_instance = Foo()
foo_foo = foo_instance.foo # Behind the scenes invokes Foo.foo.__get__(foo_instance, Foo)
Wait, yeah this is what I expect, what about the case when obj is None?
The not so typical usage (grabbing access to an unbound version of the property)
(Taking the same Foo as above)
>> Foo.foo
<__main__.cached_property at 0x178bed0>
In this case the call looks like Foo.foo.__get__(None, Foo)
__get__"...