woonizzooni

[python] RuntimeError: maximum recursion depth exceeded while getting the str of an object 본문

Programming/Python

[python] RuntimeError: maximum recursion depth exceeded while getting the str of an object

woonizzooni 2019. 7. 27. 21:55

 

샘플 코드

#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys

def f(n):
    try:
        f(n+1)
    except Exception as e:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        print("%s : %s (%d)" % (exc_type.__name__, exc_value, n))

f(1)

 

실행결과 : 

   RuntimeError : maximum recursion depth exceeded while getting the str of an object (998)

 

998번째 recursion에서 실행되지 못하고 종료됨.

이유는 python내부에서 무한 재귀 호출을 막기 위해 제한을 두기 때문.(this limit prevents infinite recursion from causing an overflow of the C stack and crashing python),

 

https://docs.python.org/3/library/exceptions.html#RecursionError

 

공식 문서 상(?)에 default recursion limit이 보이지 않아 파이썬 소스를 살펴봄.

기본 값은 1,000이고, get/set으로 조회/설정 가능함. 

/Python/ceval.c

>>> import sys
>>> sys.getrecursionlimit()
1000

 

이 값이 1000인데 실제 재귀함수는 998번째 호출됨. 약간 작게?

'작은 (<)' 조건이면 1이 더 작게 나온 셈인데.

 

5! 팩토리얼(factorial)을 예로 든 설명을 참고해보면, call stack이 쌓여지고 unwinding되어 처음으로 돌아가는데

caller frame(global execution context)이 포함되기 때문이다.

그래서 1만큼 작게 나옴

 

[결론]

 - setrecursionlimit(limit)으로 기본 임계값 수치 조정이 가능함

 - 임계값이 커지면 stack frame 증가 > overflow or crash 등의 문제가 발생할 수도 있으니,

    재귀 함수 구현이 꼭 필요한 곳이라면 base 정의로 무한 호출이 발생하지 않도록 해야함. (아래 유튜브 참고)

 - 임계값 조정은 운영체제 실행환경과 같이 조정되어야 함.

 

 

[참고]

A Beginner's Guide to Recursion. (11:26 ~ )

https://www.youtube.com/watch?v=AfBqVVKg4GE

https://stackoverflow.com/questions/40115683/why-is-the-maximum-recursion-depth-in-python-1000

https://realpython.com/python-thinking-recursively/

 

 


#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
import traceback

sys.setrecursionlimit(10)

def f(n):
    try:
        f(n+1)
    except Exception as e:
        exc_type, exc_value, exc_traceback = sys.exc_info()
        print("%s : %s (%d)" % (exc_type.__name__, exc_value, n))

def g(n):
    f(n)

def h(n):
    g(n)

f(1)

[복기]

10으로 recursion limit값을 조정하고

 

f(1) 실행 : 에러 발생 케이스의 n값이 9번 - 1번(메인 프레임) = 8

g(1) 실행 : 9 - 메인 - g(1)  = 7번, 에러 발생 케이스 n = 7

h(1) 실행 : 9 - 메인 - h(1) - g(1) = 6번, 에러 발생 케이스 n = 6

 

 

Comments