6

I have created a program that uses recursion to solve simple mazes. In the event of a rather complex maze, I get a maximum recursion depth error. I have searched that error on this website and read threads, so I believe I have a general understanding of what is occurring.

Unlike the other threads I saw, I am not trying to increase the recursion limit. sys.setrecursionlimit() is not what I am looking for. I would like to be able handle the overflow, and instead of crashing have the program print a message (print("Sorry but this maze solver was not able to finish analyzing the maze due to recursion limits)) and close.

I am aware of using try and except to handle errors, but I'm not sure if I can incorporate that to handle a maximum recursion depth error.

Martijn Pieters
  • 963,270
  • 265
  • 3,804
  • 3,187
JohnKraz
  • 109
  • 1
  • 8
  • Note that you can generally implement any recursive algorithm as a non-recursive algorithm using a queue data structure. That's one way to get around recursion limits. – jme Dec 05 '14 at 17:45
  • Hi thank you for the information JME. I am required to use recursion for this assignment (it is a class problem) – JohnKraz Dec 05 '14 at 18:11
  • @jme Any example of how to do this when you don't know how big the structure is (which is generally why most people reach for recursion)? For example, crawling a network of links on the web, or recursing through an API to get all its data. – Joe Flack Mar 29 '22 at 03:51

1 Answers1

8

A maximum recursion depth error is just another exception; you can catch the RecursionError exception (Python 3.5 or later):

try:
    solveMaze(maze)
except RecursionError as re:
    print('Sorry but this maze solver was not able to finish '
          'analyzing the maze: {}'.format(re.args[0]))

I've incorporated the error message attached to the runtime exception; for a recursion error that's maximum recursion depth exceeded.

If you need to support Python versions earlier than 3.5, you can catch the base class, RuntimeError. If you are worried about catching runtime errors that are not recursion depth errors, you could introspect the .args[0] value:

try:
    solveMaze(maze)
except RuntimeError as re:
    if re.args[0] != 'maximum recursion depth exceeded':
        # different type of runtime error
        raise
    print('Sorry but this maze solver was not able to finish '
          'analyzing the maze: {}'.format(re.args[0]))

Demo of the options:

>>> def infinity(): return infinity()
... 
>>> try:
...     infinity()
... except RecursionError as re:
...     print('Oopsie: {}'.format(re.args[0]))
... 
Oopsie: maximum recursion depth exceeded
>>> def alter_dict_size():
...     dct = {'foo': 'bar'}
...     for key in dct:
...         del dct['foo']
... 
>>> try:
...     alter_dict_size()
... except RuntimeError as re:
...     print('Oopsie: {}'.format(re.args[0]))
... 
Oopsie: dictionary changed size during iteration
>>> try:
...     infinity()
... except RuntimeError as re:
...     if re.args[0] != 'maximum recursion depth exceeded':
...         raise
...     print('Oopsie: {}'.format(re.args[0]))
... 
Oopsie: maximum recursion depth exceeded
>>> try:
...     alter_dict_size()
... except RuntimeError as re:
...     if re.args[0] != 'maximum recursion depth exceeded':
...         raise
...     print('Oopsie: {}'.format(re.args[0]))
... 
Traceback (most recent call last):
  File "<stdin>", line 2, in <module>
  File "<stdin>", line 3, in alter_dict_size
RuntimeError: dictionary changed size during iteration

Altering a dictionary size also raises a RuntimeError exception, but testing the resulting exception message allows you to differentiate.

Martijn Pieters
  • 963,270
  • 265
  • 3,804
  • 3,187
  • I'm trying to catch `RecursionError` and pickle something, but it doesn't work. It seems like certain operations in the `except RecursionError:` block are not being handled. – Joe Flack Mar 29 '22 at 03:50
  • @JoeFlack: are you certain you are not triggering another recursion error? If you are catching the exception *inside the recursing function*, further function calls will trigger another recursion exception as you are very close to the limit. – Martijn Pieters Mar 30 '22 at 11:08
  • Hmm. Actually herp derp you're right. I was pickling my 'state object' so that I could exit the program and continue where I left off. But that pickling involves a method call. Kind of annoying; seriously limits what you can do when handling a RecursionError. – Joe Flack Mar 31 '22 at 19:01
  • @JoeFlack then handle the exception at the point where you call the recursive function. If you must have access to local state from the innermost call, raise a custom exception to which you attach the data or assign to a global somewhere. Or don’t use recursion and [iterate instead](https://stackoverflow.com/q/159590). – Martijn Pieters Apr 03 '22 at 20:24