[Python-Dev] 'hasattr' is broken by design (original) (raw)
Steven D'Aprano steve at pearwood.info
Tue Aug 24 13:51:21 CEST 2010
- Previous message: [Python-Dev] 'hasattr' is broken by design
- Next message: [Python-Dev] 'hasattr' is broken by design
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]
On Tue, 24 Aug 2010 11:09:10 am Guido van Rossum wrote:
On Mon, Aug 23, 2010 at 4:56 PM, Steven D'Aprano <steve at pearwood.info> wrote: [...] > 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
But that's the thing... as far as I am concerned, a dynamically defined attribute doesn't exist. If it existed, getattr would never be called. A minor semantic difference, to be sure, but it's real to me.
Whether I should care about the difference is a separate issue.
This conversation has been valuable to me for one thing though... it reminded me of a piece of code I had written a long time ago. A simplified version:
class K(object): def getattribute(self, name): if hasattr(self, name): # no computation needed print "Attr exists" else: # compute something... print "Attr doesn't exist"
I couldn't work out why it was behaving so strangely, and rather than spend time investigating, I abandoned the whole dynamic attribute approach and did something completely different. So at least now I know why it wasn't working as I expected.
(and there are lots of other ways for attributes to be defined besides the ways you came up with just now).
I never suggested that it would be easy.
> 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.
Performance could be an issue, of course, if somebody writes an expensive getattr or property. Computed attributes should be cheap. But I'm actually more concerned about side-effects than performance. If I'm not worried about potential side-effects, I use a try...except block. If I am worried, I "Look Before You Leap". Only now I've learned that what I thought was LBYL is nothing of the sort, and hasattr gives me no protection against side-effects. That being the case, I might as well just stick to try...except and be done with it.
I'm not suggesting this is the One True Way. If others prefer hasattr, then I have no problem with that. I'm just saying that now that I know what it actually does, its value for me is minimal.
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.
Aha! The penny drops! Is that why so many methods in random.Random have an "int=int" argument? E.g.
def randrange(self, start, stop=None, step=1, int=int, default=None,
maxwidth=1L<<BPF):
I'd wondered about that.
So there you go, now I've learned two things.
-- Steven D'Aprano
- Previous message: [Python-Dev] 'hasattr' is broken by design
- Next message: [Python-Dev] 'hasattr' is broken by design
- Messages sorted by: [ date ] [ thread ] [ subject ] [ author ]