On Mon, Aug 23, 2010 at 4:56 PM, Steven D'Aprano firstname.lastname@example.org 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.