[Python-Dev] 'hasattr' is broken by design

Guido van Rossum guido at python.org
Tue Aug 24 03:09:10 CEST 2010


On Mon, Aug 23, 2010 at 4:56 PM, Steven D'Aprano <steve at pearwood.info> wrote:
> On Tue, 24 Aug 2010 06:50:19 am Guido van Rossum wrote:
>
>> > * Is there anything that hasattr(obj, key) can or should do that
>> >   can't already be done with getattr(obj, key, None)?
>> >   If not, do we really need to change anything?
>>
>> getattr(obj, 'key', None) returns None when obj.key exists and has
>> the value None. The workaround is ugly.
>
> Why do you say it's ugly? It's a short, sweet, simple two-liner:
>
> mark = object()
> getattr(obj, 'key', mark) is not mark
>
> Nothing ugly about it at all. But if somebody really objected to using a
> two lines, they could put it in a utility function.

Because if you didn't have the foresight to write that utility
function, you have to break your train of thought (aka yak shaving) to
either write it (big yak) or write those two lines (little yak, times
the number of times it happens). Whereas with hasattr() you can just
type the correct hasattr() expression in-line in the if that you
already started typing.

> It still doesn't cope with dynamically-generated attributes that are
> either expensive or have side-effects (both of which are probably poor
> design, but nevertheless I'm sure they're out there), but neither does
> the existing hasattr.
>
>
>> * Why do people typically use hasattr() instead getattr()?
>>
>> >    Aren't they are really trying to just determine
>> >    whether a key exists somewhere in the MRO?
>> >    If so, then doing anything more than that is probably a
>> > surprise.
>>
>> Most users who call hasattr() probably don't even know what MRO
>> means.
>
> Well, yes, but most users never write __getattr__ or __getattribute__
> methods either.
>
> I have always thought that hasattr() does what it says on the box: it
> tests for the *existence* of an attribute, that is, one that statically
> exists rather than being dynamically generated. In other words, it is a
> key in the instance __dict__ or is inherited from the class __dict__ or
> that of a superclass, or a __slot__.

It tests for the existence of an attribute -- how the attribute is
defined should not have to occur to you (and there are lots of other
ways for attributes to be defined besides the ways you came up with
just now).

> Now that I know that hasattr doesn't do what I thought it does or what
> the name implies it does, it has little or no utility for me. In the
> future, I'll just write a try...except block and catch errors if the
> attribute doesn't exist.

The try/except block *also* requires you to break your train of
thought. And most of the time the error case just isn't important. You
sound like you are over-engineering it and focusing too  much on
performance instead of on getting things done. Like those people who
learn that it saves an usec to copy a built-in function into a defalt
arg (def foo(arg1, len=len):  ...) and then overuse the trick even
when the time it took them to write the exra line is more than the
time they'll save in a lifetime in execution time.

-- 
--Guido van Rossum (python.org/~guido)


More information about the Python-Dev mailing list