confusion about __getattr__

David Bolen db3l at fitlinxx.com
Thu Jan 17 00:06:08 EST 2002


"Russ Cox" <rsc at plan9.bell-labs.com> writes:

> Could someone explain the error message in the
> following to me?  I apologize if it should be
> obvious, but clearly I have the wrong mental
> picture of what's going on.  
> 
> g% python
> Python 2.2+ (#0, Jan 16 2002, 19:28:19) [C] on unknown
> Type "help", "copyright", "credits" or "license" for more information.
> >>> class Test:
> ... 	def __getattr__(self, name):
> ... 		return '__getattr__ for '+name
> ... 	def __init__(self):
> ... 		self.foo = 'bar'
> ... 	def asdf(self):
> ... 		return 'jkl;'
> ... 
> >>> t=Test()
> >>> t.foo
> 'bar'
> >>> t.sdfsdfdsf
> '__getattr__ for sdfsdfdsf'
> >>> t.asdf()
> 'jkl;'
> >>> t.asdf
> Traceback (most recent call last):
>   File "<stdin>", line 1, in ?
> TypeError: 'str' object is not callable
> >>> 
> 
> What is the str object in question that isn't callable?

Python wants to print out a message like:

    <bound method Test.asdf of <__main__.Test instance at 0x007D0020>>

But in order to determine the string to be printed after the "of"
(e.g., a string representation of the class) it tries to lookup the
__repr__ method in the class.  This gets trapped by your __getattr__
which returns a string which is invalid for Python to call as
__repr__.

When writing a __getattr__ method you have to be careful that you only
handle the lookups you specifically want to trap.  Anything else
should be passed through (e.g., by checking self.__dict__ or
explicitly raising AttributeError if you want to hide everything not
handled).  Python 2.2 also added properties (if your class inherits
from "object" for new style classes) to let you trap specific
attribute accesses without having to write a general __getattr__
handler.

This does seem slightly different in Python 2.2 over earlier releases.
Earlier releases print a message such as:

    <method Test.asdf of Test instance at 007FAD9C>

which always uses the class name in the latter half of the message,
without giving the class a chance to control its representation
(whereas other references directly to the class would have used
__repr__).  My guess is this was done in 2.2 to close that
discrepancy.  In theory it should be a backwards compatible change
since prior code would have no reason to override __repr__ since it
wasn't being used, but it could tickle buggy __getattr__ method into
behaving differently in Python 2.2 than earlier versions.

--
-- David
-- 
/-----------------------------------------------------------------------\
 \               David Bolen            \   E-mail: db3l at fitlinxx.com  /
  |             FitLinxx, Inc.            \  Phone: (203) 708-5192    |
 /  860 Canal Street, Stamford, CT  06902   \  Fax: (203) 316-5150     \
\-----------------------------------------------------------------------/



More information about the Python-list mailing list