파이썬에는 재귀 횟수(최대 재귀 횟수)에 상한선이 있습니다. 호출 횟수가 많은 재귀 함수를 실행하려면 제한을 변경해야 합니다. 표준 라이브러리의 sys 모듈에 있는 기능을 사용하십시오.
재귀 횟수도 스택 크기에 따라 제한됩니다. 일부 환경에서는 표준 라이브러리의 리소스 모듈을 사용하여 최대 스택 크기를 변경할 수 있습니다(Ubuntu에서는 작동하지만 Windows 또는 Mac에서는 작동하지 않음).
다음 정보가 여기에 제공됩니다.
- 현재 재귀 횟수의 상한을 가져옵니다.
sys.getrecursionlimit()
- 재귀 횟수의 상한을 변경합니다.
sys.setrecursionlimit()
- 스택의 최대 크기 변경:
resource.setrlimit()
샘플 코드는 Ubuntu에서 실행 중입니다.
현재 재귀 제한 가져오기: sys.getrecursionlimit()
현재 재귀 제한은 sys.getrecursionlimit()로 얻을 수 있습니다.
import sys
import resource
print(sys.getrecursionlimit())
# 1000
예에서 최대 재귀 횟수는 1000이며 환경에 따라 다를 수 있습니다. 여기에서 가져오는 리소스는 나중에 사용되지만 Windows에서는 사용되지 않습니다.
예를 들어 다음과 같은 간단한 재귀 함수를 사용합니다. 양의 정수 n이 인수로 지정되면 호출 횟수는 n회입니다.
def recu_test(n):
if n == 1:
print('Finish')
return
recu_test(n - 1)
상한선 이상 재귀를 시도하면 오류(RecursionError)가 발생합니다.
recu_test(950)
# Finish
# recu_test(1500)
# RecursionError: maximum recursion depth exceeded in comparison
sys.getrecursionlimit()에서 얻은 값은 엄격하게는 최대 재귀 횟수가 아니라 Python 인터프리터의 최대 스택 깊이이므로 재귀 횟수가 이 값보다 약간 적더라도 오류(RecursionError)가 발생합니다. 제기되다.
再帰限界は、再帰の限界ではなく、pythoninta-prita의 스택의 最大深度입니다.
python – Max recursion is not exactly what sys.getrecursionlimit() claims. How come? – Stack Overflow
# recu_test(995)
# RecursionError: maximum recursion depth exceeded while calling a Python object
재귀 제한 변경: sys.setrecursionlimit()
재귀 횟수의 상한선은 sys.setrecursionlimit()로 변경할 수 있습니다. 상한은 인수로 지정됩니다.
더 깊은 재귀를 수행할 수 있습니다.
sys.setrecursionlimit(2000)
print(sys.getrecursionlimit())
# 2000
recu_test(1500)
# Finish
지정된 상한이 너무 작거나 너무 크면 오류가 발생합니다. 이 제약 조건(한계 자체의 상한 및 하한)은 환경에 따라 다릅니다.
제한의 최대값은 플랫폼에 따라 다릅니다. 심층 재귀가 필요한 경우 플랫폼에서 지원하는 범위 내에서 더 큰 값을 지정할 수 있지만 이 값이 너무 크면 충돌이 발생한다는 점에 유의하십시오.
If the new limit is too low at the current recursion depth, a RecursionError exception is raised.
sys.setrecursionlimit() — System-specific parameters and functions — Python 3.10.0 Documentation
sys.setrecursionlimit(4)
print(sys.getrecursionlimit())
# 4
# sys.setrecursionlimit(3)
# RecursionError: cannot set the recursion limit to 3 at the recursion depth 1: the limit is too low
sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000
# sys.setrecursionlimit(10 ** 10)
# OverflowError: signed integer is greater than maximum
최대 재귀 횟수도 다음에 설명하는 것처럼 스택 크기에 의해 제한됩니다.
스택의 최대 크기 변경: resource.setrlimit()
sys.setrecursionlimit()에 큰 값이 설정되어 있어도 재귀 횟수가 많으면 실행되지 않을 수 있습니다. 다음과 같이 세그멘테이션 오류가 발생합니다.
sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000
recu_test(10 ** 4)
# Finish
# recu_test(10 ** 5)
# Segmentation fault
Python에서는 표준 라이브러리의 리소스 모듈을 사용하여 최대 스택 크기를 변경할 수 있습니다. 그러나 리소스 모듈은 Unix 전용 모듈이며 Windows에서는 사용할 수 없습니다.
- Unix Specific Services — Python 3.10.0 Documentation
- resource — Resource usage information — Python 3.10.0 Documentation
resource.getrlimit()를 사용하면 인수에 지정된 리소스의 제한을 (soft limit, hard limit)의 튜플로 얻을 수 있습니다. 여기에서 현재 프로세스의 호출 스택의 최대 크기를 나타내는 리소스로 resource.RLIMIT_STACK을 지정합니다.
- resource.getrlimit() — Resource usage information — Python 3.10.0 Documentation
- resource.RLIMIT_STACK — Resource usage information — Python 3.10.0 Documentation
print(resource.getrlimit(resource.RLIMIT_STACK))
# (8388608, -1)
예에서 소프트 제한은 8388608(8388608 B = 8192KB = 8MB)이고 하드 제한은 -1(무제한)입니다.
resource.setrlimit()를 사용하여 리소스 제한을 변경할 수 있습니다. 여기에서 소프트 제한도 -1(제한 없음)로 설정됩니다. 또한 상수 resource.RLIM_INFINIT를 사용하여 무제한 제한을 나타낼 수 있습니다.
스택 크기 변경 이전에 세그멘테이션 오류로 인해 수행할 수 없었던 Deep recursion을 이제 수행할 수 있습니다.
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
print(resource.getrlimit(resource.RLIMIT_STACK))
# (-1, -1)
recu_test(10 ** 5)
# Finish
여기서는 간단한 실험을 위해 소프트 리미트를 -1(무제한)로 설정했지만 실제로는 적절한 값으로 제한하는 것이 더 안전할 것이다.
또한 내 Mac에서도 무제한 소프트 제한을 설정하려고 하면 다음 오류가 발생했습니다.ValueError: not allowed to raise maximum limit
sudo로 스크립트를 실행해도 도움이 되지 않았습니다. 시스템에 의해 제한될 수 있습니다.
수퍼유저의 유효 UID를 가진 프로세스는 제한 없음을 포함하여 모든 합당한 제한을 요청할 수 있습니다.
그러나 시스템에서 부과한 제한을 초과하는 요청은 여전히 ValueError가 발생합니다.
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation
Windows에는 리소스 모듈이 없으며 mac은 시스템 제한으로 인해 최대 스택 크기를 변경할 수 없습니다. 어떤 방법으로든 스택 크기를 늘릴 수 있다면 세그먼테이션 오류를 해결할 수 있어야 하는데 이를 확인하지 못했습니다.