'if foo' calls getattr?!?

Joe Strout joe at strout.net
Mon Aug 30 13:50:23 EDT 1999

[[ This message was both posted and mailed: see
   the "To," "Cc," and "Newsgroups" headers for details. ]]

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.  We eventually tracked it down to a seemingly
innocent test, basically, "if foo: self.myfoo = foo".  The "if foo" was
invoking foo.__getattr__ (which is very expensive).

I can think of no reason why it should be this way, but it is.  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?  Is
there some other way to check whether I have a reference to an object
that doesn't involve a function call?

-- Joe

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

def testB():
   global getattrcount
   getattrcount = 0
   foo = Foo()
   for i in range(42):
      if id(foo) != id(None): pass
   print "calls when using id:", getattrcount

testA()     # results in 84 calls!
testB()     # results in 0 calls.

|    Joseph J. Strout           Biocomputing -- The Salk Institute |
|    joe at strout.net             http://www.strout.net              |
Check out the Mac Web Directory!    http://www.strout.net/macweb.cgi

More information about the Python-list mailing list