[Tutor] class.__repr__: 'str' object is not callable???

Danny Yoo dyoo@hkn.eecs.berkeley.edu
Thu May 1 16:42:01 2003


On Wed, 30 Apr 2003 pan@uchicago.edu wrote:

> Can someone tell me what the hell is happening in the following code?

[some text cut]

> >>> class aClass:
> ..     def __init__(self):pass
> ..     def __repr__(self):
> ..     	   return 'this is aClass'
> ..     def __getattr__(self, name):
> ..     	   print 'getting attr'       #<==== [A]
> ..     	   return 'returned value'
> ..
> >>>
> >>> a=aClass()
> >>> a
> this is aClass
>
> >>> print a
>  getting attr
> Traceback (most recent call last):
>   File "<interactive input>", line 1, in ?
> TypeError: 'str' object is not callable




Hi Pan,


In Python, even the methods of a class are 'attributes':

###
>>> class MyClass:
...     def __init__(self):
...         self.name = 'pan'
...     def some_method(self):
...         return 42 ** 2
...
>>> inst = MyClass()
>>> inst.name
'pan'
>>> inst.some_method
<bound method MyClass.some_method of <__main__.MyClass instance at
0x814728c>>
###



Notice that we can get at data attributes and methods using the same
syntax.  The one major thing that distinguishes a method from any other
data thing is that we can "apply" it --- to evaluate it as an action.
But we know this already with our experience with functions: we know that
functions are things that are, in some sense, just like other objects:

###
>>> def add(x, y): return x + y
...
>>> def mul(x, y): return x * y
...
>>> list_of_functions = [add, mul]
>>> list_of_functions
[<function add at 0x815893c>, <function mul at 0x8157a54>]
>>> list_of_functions[0]
<function add at 0x815893c>
>>> f = list_of_functions[0]
>>> f(11, 31)
42
>>> list_of_functions[1](11, 31)
341
###




So there's no barrier between the methods in our class and our other
instance attributes.  By the way, this can cause some accidental problems
for people who expect the two to live in different worlds:

###
>>> class BuggyClass:
...     def __init__(self):
...         self.name = 'pan'
...     def name(self):
...         return "My name is " + self.name
...
>>>
>>>
>>> b = BuggyClass()
>>>
>>> b.name()                 ## Review Question: why doesn't this work?
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: 'str' object is not callable
>>>
>>>
>>>
>>> BuggyClass.name(b)       ## Advanced question: why does this work?
'My name is pan'
###


Java programmers, in particular, may need to be careful of old habits,
because it's one language that puts variables and methods in different
'namespaces'.  In Java, the collision between method names and data
attribute names can't occur.  This might be a good thing or a bad thing,
depending on your perspective.  (Personally, I like Python's method better
for reasons of unity.)



Anyway, back to your question: when we do a 'print' on an object in
Python, if that object isn't a string yet, Python will automatically call
str() on that object to get a fairly readable representation of that
object as a string.  Python looks for an __str__() method in our class,
but doesn't find one.  But since aClass defines an alternative way of
getting attributes --- that __getattr__()  method! --- that's what Python
will try to use.



The path to the error message is subtly convoluted.  But does it make
sense now?  Please feel free to ask more questions about this till it
starts getting less fuzzy.  *grin*



Good luck to you!