Opened 5 years ago

Closed 5 years ago

Last modified 5 years ago

#30278 closed Bug (invalid)

Using del on uncalled cached_property throws exception.

Reported by: Matthew Schinckel Owned by: nobody
Component: Utilities Version: dev
Severity: Normal Keywords: cached_property
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

It's explicitly documented that you may use del (or delattr) to force a cached_property to recalculate the next time it's called.

However, if you try to del a cached_property that has never been evaluated, then an AttributeError is raised.

There doesn't seem to be a way to detect if a cached_property has been evaluated or not, as hasattr(foo, 'bar') results in the evaluation of the cached_property.

It's entirely possible that this is something that is beyond the capability of the way cached_property is implemented, but it still feels wrong to me.

(Likewise, if you attempt to del foo.bar twice without evaluation in between, you will raise an AttributeError).

Change History (9)

comment:1 by Curtis Maloney, 5 years ago

The problem here is (a) fundamental to how Python works, and (b) complicated by cached_property "cheating".

So, cached_property works by saving the value it calculates into the instances __dict__.

This means next time that attribute is accessed, _Python_ will check __dict__ first, and not even try the property.

Calling del will remove the entry from the instances __dict__. However, if it's not there, it will fall back to the class's property.

This causes the attribute error, because the property class does not have a __delete__ method.

If it did have a __delete__ method, Python's lookup would differ, and it would _not_ check __dict__ before calling the property. (the official documentation mentions this about __get__, but a simple test shows it applies to __delete__ equally)

https://docs.python.org/3/reference/datamodel.html#invoking-descriptors

So, we can't have _both_ - if we support del on uninvoked cached_property we lose the utility of cached_property (or, at least, the performance)

comment:2 by Matthew Schinckel, 5 years ago

Gotcha.

(In practice, it's possible to catch an exception raised by code that is calling del foo.bar when it's possible foo.bar has not been referenced yet, so I guess that will have to do).

comment:3 by Matthew Schinckel, 5 years ago

Resolution: invalid
Status: newclosed

comment:4 by Carlton Gibson, 5 years ago

Great discussion. Thank you both!

Just before this disappears over the horizon, is it worth adjusting the del example in the docs here do we think?

in reply to:  4 comment:5 by Matthew Schinckel, 5 years ago

Replying to Carlton Gibson:

Just before this disappears over the horizon, is it worth adjusting the del example in the docs here do we think?

I did wonder that: maybe it is worth having a note in the docs.

comment:6 by Tim Graham <timograham@…>, 5 years ago

In c3c2ec54:

Refs #30278 -- Doc'd behavior of del on an unaccessed cached_property.

Thanks to Curtis Maloney for the description of the problem.

comment:7 by Tim Graham <timograham@…>, 5 years ago

In f141704:

[2.2.x] Refs #30278 -- Doc'd behavior of del on an unaccessed cached_property.

Thanks to Curtis Maloney for the description of the problem.
Backport of c3c2ec54f59428cdf0a35abce594fd2ada35c209 from master

comment:8 by Tim Graham <timograham@…>, 5 years ago

In b9455b01:

Refs #30278 -- Fixed link in cached_property docs.

comment:9 by Tim Graham <timograham@…>, 5 years ago

In fc708f3:

[2.2.x] Refs #30278 -- Fixed link in cached_property docs.

Backport of b9455b010e41d1c6e68faa11115212d50de3c231 from master.

Note: See TracTickets for help on using tickets.
Back to Top