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 <st...@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 _______________________________________________ Python-Dev mailing list Python-Dev@python.org http://mail.python.org/mailman/listinfo/python-dev Unsubscribe: http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com