'Mixing @cached_property and __getattr__ properly
Mixing functools.cached_property and __getattr__ works well, except... when Exception raises:
from functools import cached_property
class A:
def __init__(self):
self.exists = 1
class B:
def __init__(self, a):
self.a = a
self.b = 1
def __getattr__(self, name):
return getattr(self.a, name)
@cached_property
def cached_func(self):
return self.not_exists
def func(self):
return self.not_exists
a = A()
b = B(a)
b.cached_func # 'A' object has no attribute 'cached_func'
b.func() # -> 'A' object has no attribute 'not_exists'
The Exception raised when using cached_property is not explicit at all -- if not wrong. Is there a way to work around this?
Solution 1:[1]
OK, I found a way by adding a new decorator that will catch AttributeError before its propagation.
I created a specific Exception to better handle it during runtime.
from functools import cached_property, wraps
class NestedAttributeError(RuntimeError):
"""Specific exception for describing nested __getattr__ error"""
def intercept_AttributeError(func):
@wraps(func)
def wrapped(*args, **kwargs):
try:
return func(*args, **kwargs)
except AttributeError as exc:
raise NestedAttributeError(exc)
return wrapped
class A:
def __init__(self):
self.exists = 1
def __repr__(self):
return "AObj"
class B:
def __init__(self, a):
self.a = a
self.b = 1
def __repr__(self):
return "BObj"
def __getattr__(self, name):
#return getattr(self.a, name)
try:
attr = getattr(self.a, name)
except AttributeError as exc:
raise NestedAttributeError(exc)
return attr
@cached_property
@intercept_AttributeError
def cached_func(self):
a = self.not_exists
return a + 1
def func(self):
return self.not_exists
b = B(A())
b.cached_func # -> NestedAttributeError: 'A' object has no attribute 'not_exists'
b.func() # -> NestedAttributeError: 'A' object has no attribute 'not_exists'
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Nic |
