'if foo' calls getattr?!?

Gordon McMillan gmcm at hypernet.com
Mon Aug 30 15:21:25 EDT 1999


Joe Strout wrote:
 
> Doing some profiling on Graphite this weekend, we found a very
> curious thing: a gazillion calls to __getattr__ on one of our
> classes, where we expected to find none. 
> 
> Below is a very simple stand-alone demonstration.  It leads me to
> the absurd idiom of saying "if id(foo) != id(None)" when I really
> mean "if foo", just because using id() avoids the __getattr__ call.
> 
> Can anybody explain why this should be?  Is it a bug in Python? 
> 
> getattrcount = 0
> 
> class Foo:
>    def __getattr__(self,attr):
>       global getattrcount
>       getattrcount = getattrcount+1
>       return self.__dict__[attr]
> 
> def testA():
>    global getattrcount
>    getattrcount = 0
>    foo = Foo()
>    for i in range(42):
>       if foo: pass
>    print "calls due to 'if foo':", getattrcount

If you read the Timbot's posts, you'd know it's not the __getattr__, 
it's the "42"!

More instructive is to see what "attr" is: First it's __nonzero__, 
and then it's __len__. Python is doing whatever it can to determine 
whether your object considers itself "true" or not. Which leads to 
the conclusion that "if X" doesn't test if X exists, but whether X is 
"true" according to some interpretation.

You've found one solution. You don't say what the alternative to foo 
is; if that alternative is non-existance, you've got a NameError.  So 
I'll assume the alternative is None.

In which case "if foo is not None" will be the fastest and 
closest-to-your-intention test possible. (But "if foo != None" will 
get you right back to where you are now!).

- Gordon




More information about the Python-list mailing list