[Python-ideas] the error that raises an AttributeError should be passed to __getattr__

Chris Angelico rosuav at gmail.com
Mon Jun 19 23:10:54 EDT 2017


On Tue, Jun 20, 2017 at 12:26 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> On Tue, Jun 20, 2017 at 11:31:34AM +1000, Chris Angelico wrote:
>
>> Why not just write cross-version-compatible code as
>>
>> def __getattr__(self, name, error=None):
>>
>> ? Is there something special about getattr?
>
> You've still got to write it in the first place. That's a pain,
> especially since (1) it doesn't do you any good before 3.7 if not later,
> and (2) even if this error parameter is useful (which is yet to be
> established), it's a pretty specialised use. Most of the time, you
> already know the name that failed (its the one being looked up).

Gotcha, yep. I was just confused by your two-parter that made it look
like it would be hard (or impossible) to write code that would work on
both 3.6 and the new protocol.

> Perhaps a better approach is to prevent descriptors from leaking
> AttributeError in the first place? Change the protocol so that if
> descriptor.__get__ raises AttributeError, it is caught and re-raised as
> RuntimeError, similar to StopIteration and generators.

This can't be done globally, because that's how a descriptor can be
made conditional (it raises AttributeError to say "this attribute does
not, in fact, exist"). But it's easy enough - and safe enough - to do
it just for your own module, where you know in advance that any
AttributeError is a leak. The way generators and StopIteration
interact was more easily fixed, because generators have two legitimate
ways to emit data (yield and return), but there's no easy way for a
magic method to say "I don't have anything to return" other than an
exception.

Well, that's not strictly true. In JavaScript, they don't raise
StopIteration from iterators - they always return a pair of values
("done" and the actual value, where "done" is either false for a yield
or true for a StopIteration). That complicates the normal case but it
does make the unusual case a bit easier. Also, it's utterly and
fundamentally incompatible with the current system, so it'd have to be
a brand new competing protocol.

ChrisA


More information about the Python-ideas mailing list