
2017-06-25 Greg Ewing <greg.ewing@canterbury.ac.nz> dixit:
(2) There's a *specific* problem with property where a bug in your getter or setter that raises AttributeError will be masked, appearing as if the property itself doesn't exist. [...] Case 2 needs to be addressed within the method concerned on a case-by-case basis. If there's a general principle there, it's something like this: If you're writing a method that uses an exception as part of it's protocol, you should catch any incidental occurrences of the same exception and reraise it as a different exception.
I don't think there's anything more the Python language could do to help with either of those.
In "case 2", maybe some auto-zeroing flag (or even a decrementing counter?) could be useful? Please, consider the following draft: class ExtAttributeError(AttributeError): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self._propagate_beyond = True # of course this should be a class and it should support not only # getters but also setters and deleters -- but you get the idea... def new_property(func): def wrapper(self): try: return func(self) except AttributeError as exc: if getattr(exc, '_propagate_beyond', False): exc._propagate_beyond = False raise raise RuntimeError( f'Unexpected {exc.__class__.__name__}') from exc return wrapper Then we could have: class Spam: @new_property def target(self): if len(self.targgets) == 1: return self.targets[0] raise ExtAttributeError( 'only exists when this has exactly one target') Cheers. *j