Easily. You could have a container class with a recursion-unsafe __str__
or __repr__
that ends up in a reference loop:
import numpy
x = numpy.empty([1], dtype=object)
x[0] = x
str(x) # RuntimeError: maximum recursion depth exceeded
Or just a really highly nested object:
x = []
for i in xrange(2000):
x = [x]
str(x) # RuntimeError: maximum recursion depth exceeded while getting the repr of a list
Heck, even with just built-in types, you could get something a lot worse than an exception:
x = {}
for i in range(1000000):
x = {1: x}
str(x) # python.exe has stopped working
# Windows can check online for a solution to the problem.
That's a C stack overflow, since dict_repr
doesn't (currently) use Py_EnterRecursiveCall
. You can't catch that with an except
block!
Back to the more mundane errors, you could have a weakref.proxy
to a dead object:
import weakref
class Foo(object):
pass
str(weakref.proxy(Foo())) # ReferenceError: weakly-referenced object no longer exists
Or you could just write a class that raises whatever you want in __str__
or __repr__
:
class Foo(object):
def __str__(self):
raise Exception
str(Foo()) # Raises an Exception
Specific to Python 2, you could get a case where print
ing an object produces partial output and then raises an exception, even though it ostensibly should have never reached the stage of printing anything:
class Foo(object):
def __repr__(self):
raise Exception
print [Foo()] # Prints a single opening bracket, then raises an Exception!
This is due to the obsolete tp_print
C-level hook.
You could also get a Python 2-specific UnicodeEncodeError
when str
-ing a unicode
object that contains non-ASCII characters, since Python 2 str
objects are bytestrings:
str(u'\u1000') # Fails on Python 2 only