[Python-bugs-list] [ python-Bugs-752221 ] print in __getattr__ causes seg fault
SourceForge.net
noreply@sourceforge.net
Sun, 15 Jun 2003 06:15:47 -0700
Bugs item #752221, was opened at 2003-06-10 16:58
Message generated for change (Comment added) made by sjones
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=752221&group_id=5470
Category: Python Interpreter Core
Group: Python 2.3
Status: Open
Resolution: None
Priority: 5
Submitted By: Christopher K. Paulicka (paulicka)
Assigned to: Nobody/Anonymous (nobody)
Summary: print in __getattr__ causes seg fault
Initial Comment:
[~/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
----------------------------------------------------------------------
Comment By: Shannon Jones (sjones)
Date: 2003-06-15 08:15
Message:
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.
----------------------------------------------------------------------
Comment By: Brett Cannon (bcannon)
Date: 2003-06-15 02:48
Message:
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.
----------------------------------------------------------------------
Comment By: Shannon Jones (sjones)
Date: 2003-06-13 20:57
Message:
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.
----------------------------------------------------------------------
Comment By: Christopher K. Paulicka (paulicka)
Date: 2003-06-13 19:20
Message:
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...
----------------------------------------------------------------------
Comment By: Raymond Hettinger (rhettinger)
Date: 2003-06-10 22:09
Message:
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.
----------------------------------------------------------------------
You can respond by visiting:
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=752221&group_id=5470