Skip to content
Advertisement

Python additional print() impacts printed counter value

The below provided code shows for me unexpected and strange behavior. With not out-commented print statement the final value of the counter variable differs from the value with out-commented print statement. How can an inserted print() impact the final value of the counter ‘cnt’?

Here the output with the print statement printing:

sys: maxRecursionDepth = 10
  > f(s) 0
>>> f(s) 1
  > f(s) 1
>>> f(s) 2
f() maxRecursionDepth =  2

And here the output with the out-commented print:

sys: maxRecursionDepth = 10
>>> f(s) 1
>>> f(s) 2
f() maxRecursionDepth =  3

And here the code which shows this for me strange effect I can’t explain how it comes:

from sys import getrecursionlimit, setrecursionlimit
setrecursionlimit(10)
print(f'sys: maxRecursionDepth = {getrecursionlimit()}')
cnt = 0
def f(s):
    global cnt
    #print('  >', s, cnt) # <<< CHANGES the final value of 'cnt' !!!
    cnt += 1
    print('>>>', s, cnt)
    eval(s)
# ---
try:
    f("f(s)")
except RecursionError:
    print(f'f() maxRecursionDepth =  {cnt}')
    # RecursionError: maximum recursion depth exceeded

Advertisement

Answer

As already pointed out by Michael Butscher in the comments the core of the confusion which lead to asking the question was to erroneously believe that only recursive calls to the function itself in a function can be a reason for an RecursionError

The recursion limit is actually the maximum number of stack frames. Each call to a function (even “print”) temporarily adds a stack frame. If the limit is exceeded by the print-call, the exception is raised. If un-commented, it happens before “cnt” is incremented, otherwise after the increment.

Below the evidence of the above showing that the RecursionError can and was actually caused by print().

>>> f(s) 1
>>> f(s) 2
Traceback (most recent call last):
  File "test.py", line 151, in <module>
    f("f(s)")
  File "test.py", line 150, in f
    eval(s)
  File "<string>", line 1, in <module>
  File "test.py", line 150, in f
    eval(s)
  File "<string>", line 1, in <module>
  File "test.py", line 149, in f
    print('>>>', s, cnt)
RecursionError: maximum recursion depth exceeded while calling a Python object
# ======================================================================
  > f(s) 0
>>> f(s) 1
  > f(s) 1
>>> f(s) 2
Traceback (most recent call last):
  File "test.py", line 151, in <module>
    f("f(s)")
  File "test.py", line 150, in f
    eval(s)
  File "<string>", line 1, in <module>
  File "test.py", line 150, in f
    eval(s)
  File "<string>", line 1, in <module>
  File "test.py", line 147, in f
    print('  >', s, cnt) # <<< CHANGES the final value of 'cnt' !!!
RecursionError: maximum recursion depth exceeded while calling a Python object

Below the code creating both of the above Tracebacks. Please notice that your own run of the code can lead to another result because depending on how many frames are already on the stack when running this code the code can fail at another statement as that one pointed out in above Traceback.

from sys import getrecursionlimit, setrecursionlimit
setrecursionlimit(10)
print(f'sys: maxRecursionDepth = {getrecursionlimit()}')
cnt = 0
def f(s):
    global cnt
    # print('  >', s, cnt) # <<< CHANGES the final value of 'cnt' !!!
    cnt += 1
    print('>>>', s, cnt)
    eval(s)
f("f(s)")
User contributions licensed under: CC BY-SA
7 People found this is helpful
Advertisement