This issue tracker has been migrated to GitHub, and is currently read-only.
For more information, see the GitHub FAQs in the Python's Developer Guide.

classification
Title: print in __getattr__ causes seg fault
Type: Stage:
Components: Interpreter Core Versions: Python 2.3
process
Status: closed Resolution: out of date
Dependencies: Superseder:
Assigned To: Nosy List: brett.cannon, paulicka, rhettinger, sjones
Priority: normal Keywords:

Created on 2003-06-10 21:58 by paulicka, last changed 2022-04-10 16:09 by admin. This issue is now closed.

Messages (7)
msg16338 - (view) Author: Christopher K. Paulicka (paulicka) Date: 2003-06-10 21:58
[~/site-packages/WorldPlay/] paulicka@Sliver-14:56:32
$ python
Python 2.3a2+ (#4, Mar  2 2003, 17:13:46) 
[GCC 3.1 20020420 (prerelease)] on darwin
Type "help", "copyright", "credits" or "license" for more 
information.
>>> class A:
...     def __getattr__(self,name):
...             return 3
... 
>>> a=A()
>>> a.c
3
>>> class B:
...     def __getattr__(self,name):
...             print self, name
...             return 3
... 
>>> b=B()
>>> b.c
Segmentation fault
[~/site-packages/WorldPlay/] paulicka@Sliver-14:57:14
$ 

$ uname -a
Darwin Sliver.local. 6.6 Darwin Kernel Version 6.6: Thu 
May  1 21:48:54 PDT 2003; root:xnu/xnu-344.34.obj~1/
RELEASE_PPC  Power Macintosh powerpc
msg16339 - (view) Author: Raymond Hettinger (rhettinger) * (Python committer) Date: 2003-06-11 03:09
Logged In: YES 
user_id=80475

Can you try this one on the beta release to see if it is still a 
problem.  I cannot reproduce the segfault on a Windows 
build.
msg16340 - (view) Author: Christopher K. Paulicka (paulicka) Date: 2003-06-14 00:20
Logged In: YES 
user_id=45461

Actually, I can't use the beta, because I used the MacOS Kitchen 
Sink combination of Framework Python, Pygame and PyOpenGL.

I tried building from the CVS repository, but had problems, so 
just moved on...
msg16341 - (view) Author: Shannon Jones (sjones) Date: 2003-06-14 01:57
Logged In: YES 
user_id=589306

I tried running with current CVS and got the following
results on Linux:

Python 2.3b1+ (#3, Jun 13 2003, 07:56:14)
[GCC 3.2.2 20030222 (Red Hat Linux 3.2.2-5)] on linux2
Type "help", "copyright", "credits" or "license" for more
information.
>>> class A:
...     def __getattr__(self, name):
...             return 3
...
>>> a = A()
>>> a.c
3
>>> class B:
...     def __getattr__(self, name):
...             print self, name
...             return 3
...
>>> b = B()
>>> b.c
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
  File "<stdin>", line 3, in __getattr__
  File "<stdin>", line 3, in __getattr__
  File "<stdin>", line 3, in __getattr__
  File "<stdin>", line 3, in __getattr__
[Repeats lots of times]
  File "<stdin>", line 3, in __getattr__
RuntimeError: maximum recursion depth exceeded
>>> class C:
...     def __init__(self):
...             self.x = 5
...     def __getattr__(self, name):
...             print self.x
...             return 3
...
>>> c = C()
>>> c.c
5
3

$ uname -a
Linux localhost 2.4.20-18.9 #1 Thu May 29 06:54:41 EDT 2003
i686 athlon i386 GNU/Linux

-------------------------------------------------
Note that I can print things from getattr, it is just
printing self that gets me in trouble.
msg16342 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2003-06-15 07:48
Logged In: YES 
user_id=357491

I get a RuntimeError under OS X just like sjones but only with a 
classic class.  What else that is interesting is that if I just type in 
the instance name and hit enter it also has the RuntimeError.

I checked the bytecode and both are the same so there isn't 
some funky difference there.  Must be some way that classic 
classes handle self compared to new-style and how __getattr__ 
is dealt with.
msg16343 - (view) Author: Shannon Jones (sjones) Date: 2003-06-15 13:15
Logged In: YES 
user_id=589306

I did some research and thinking on this problem, and here
is what I think is happening.

1. When you print self inside __getattr__, Python calls
repr(self) to figure out how to print that.
2. repr(self) attempts to call self.__repr__().
3. Since you didn't define __repr__ for this class,
__getattr__ is called to look up the name.
4. __getattr__ attempts to print self again, and you are now
in an infinite loop.

For more information, do a Google Groups search for "Obscure
__getattr__ behavior" which should bring you to the thread
at http://tinyurl.com/ecsh (hope that works, heh). It even
mentions the difference bcannon mentioned between old and
new style classes.

You could solve the problem by defining your own __repr__
(and __str__ for similar reasons). Or you can raise
AttributeError in __getattr__ if name is __repr__ or __str__
so that Python reverts back to defaults for these functions.

Here is a way to write your class so that it does what you want:

>>> class B:
...     def __getattr__(self, name):
...             if name == '__repr__' or name == '__str__':
...                     raise AttributeError
...             print self, name
...             return 3
...
>>> b = B()
>>> b.c
<__main__.B instance at 0x81c785c> c
3


I'm leaning toward the opinion that the infinite loop
behavior is not a bug in Python. Even though the result
wasn't expected, Python was doing exactly as told.

However, the Segmentation Fault you got on your system is
probably a bug. That seems related to your OS / build of
Python though. Can anyone duplicate the segfault?

Maybe Python isn't catching the infinite recursion fast
enough and your stack is overflowing (just a wild guess).
Try running some code like this and see if you get a
RuntimeError or a segfault:

def f():
    f()

Then call f() to see what error you get.

msg16344 - (view) Author: Brett Cannon (brett.cannon) * (Python committer) Date: 2003-06-15 21:13
Logged In: YES 
user_id=357491

Sounds reasonable to me.  Building off of this, I realized why this 
doesn't loop for new-style classes; __getattr__ is assigned lowest 
priority in the attribute lookup order.  This means object's 
__str__ kicks in before __getattr__ is ever called when trying to 
resolve for __str__ for the print statement.

And since I am running OS X and cannot reproduce this with 
Python 2.3b1 I am going to close this bug fix.

Thanks for the help, sjones.
History
Date User Action Args
2022-04-10 16:09:08adminsetgithub: 38627
2003-06-10 21:58:52paulickacreate