pydanny / cached-property

A decorator for caching properties in classes.
BSD 3-Clause "New" or "Revised" License
688 stars 78 forks source link

Cached properties error with named tuples. #168

Open Qu4tro opened 5 years ago

Qu4tro commented 5 years ago

Hello there. Currently there's no way to use cached properties with namedTuples (or other immutable classes implemented the same way)

Trace:

AttributeError                            Traceback (most recent call last)
<ipython-input-3-7deeb8fbc12c> in <module>
----> 1 r.undirected

~/.local/share/virtualenvs/myvenv/lib/python3.7/site-packages/cached_property.py in __get__(self, obj, cls)
     33             return self._wrap_in_coroutine(obj)
     34 
---> 35         value = obj.__dict__[self.func.__name__] = self.func(obj)
     36         return value
     37 

AttributeError: 'MyClass' object has no attribute '__dict__'

Reproduced in https://github.com/Qu4tro/cachedproperty_immutable_classes

There was a change in python 3.5.1 and NamedTuple no longer has the __dict__ attribute. More information here: https://stackoverflow.com/a/34166617

I totally understand why it's failing, so my question is:

Lmk what you think.

atemate commented 4 years ago

As a workaround, use dataclass instead of namedtuple:

from cached_property import cached_property
from dataclasses import dataclass

@dataclass(frozen=True)
class A:
    x: int
    @cached_property
    def foo(self)  -> int:
        print('A.foo called')
        return self.x + 10

a = A(1)
a.foo  # 'A.foo called'
a.foo
Qu4tro commented 4 years ago

Yeah, it's also useful outside of this library because functools.cached_property also doesn't work with NamedTuples.

If anyone is here finding for suggestions, I've also been using functools.lru_cache for a while now, without a problem. I've kinda described it here: https://github.com/pydanny/cached-property/pull/137#issuecomment-526369393 .