What is a lazy property?

properties, python, webapp2

Solution

It is a `property` decorator that gets out of the way after the first call. It allows you to auto-cache a computed value.

The standard library `@property` decorator is a data descriptor object and is always called, even if there is an attribute on the instance of the same name.

The `@cached_property` decorator on the other hand, only has a `__get__` method, which means that it is not called if there is an attribute with the same name already present. It makes use of this by setting an attribute with the same name on the instance on the first call.

Given a `@cached_property`-decorated `bar` method on an instance named `foo`, this is what happens:

Python resolves `foo.bar`. No `bar` attribute is found on the instance.

Python finds the `bar` descriptor on the class, and calls `__get__` on that.

The `cached_property` `__get__` method calls the decorated `bar` method.

The `bar` method calculates something, and returns the string `'spam'`.

The `cached_property` `__get__` method takes the return value and sets a new attribute `bar` on the instance; `foo.bar = 'spam'`.

The `cached_property` `__get__` method returns the `'spam'` return value.

If you ask for `foo.bar` again, Python finds the `bar` attribute on the instance, and uses that from here on out.

Also see the source code for the original Werkzeug implementation:

# implementation detail: this property is implemented as non-data
# descriptor.  non-data descriptors are only invoked if there is
# no entry with the same name in the instance's __dict__.
# this allows us to completely get rid of the access function call
# overhead.  If one choses to invoke __get__ by hand the property
# will still work as expected because the lookup logic is replicated
# in __get__ for manual invocation.

Note that as of Python 3.8, the standard library has a similar object, `@functools.cached_property()`. It's implementation is a little bit more robust, it guards against accidental re-use under a different name, produces a better error message if used on an object without a `__dict__` attribute or where that object doesn't support item assignment, and is also thread-safe.

Problem

While looking through the webapp2 documentation online, I found information on the decorator: `webapp2.cached_property` In the documentation, it says: A decorator that converts a function into a lazy property. My question is: → What is a lazy property?

Original source