En Python, il existe une limite supérieure au nombre de récursions (le nombre maximum de récursions). Pour exécuter une fonction récursive avec un grand nombre d'appels, il est nécessaire de modifier cette limite. Utilisez les fonctions du module sys de la bibliothèque standard.
Le nombre de récursions est également limité par la taille de la pile. Dans certains environnements, le module ressource de la bibliothèque standard peut être utilisé pour modifier la taille maximale de la pile (cela a fonctionné sur Ubuntu, mais pas sur Windows ou mac).
Les informations suivantes sont fournies ici.
- Obtenir la limite supérieure du nombre actuel de récursions :
sys.getrecursionlimit()
- Modifier la limite supérieure du nombre de récursions :
sys.setrecursionlimit()
- Modifier la taille maximale de la pile :
resource.setrlimit()
L'exemple de code fonctionne sur Ubuntu.
Obtenir la limite de récursion actuelle : sys.getrecursionlimit()
La limite de récursion actuelle peut être obtenue avec sys.getrecursionlimit().
import sys
import resource
print(sys.getrecursionlimit())
# 1000
Dans l'exemple, le nombre maximal de récursions est de 1000, ce qui peut varier en fonction de votre environnement. Notez que la ressource que nous importons ici sera utilisée plus tard, mais pas sous Windows.
À titre d'exemple, nous allons utiliser la fonction récursive simple suivante. Si un nombre entier positif n est spécifié comme argument, le nombre d'appels sera de n fois.
def recu_test(n):
if n == 1:
print('Finish')
return
recu_test(n - 1)
Une erreur (RecursionError) sera levée si vous essayez d'effectuer une récursion plus que la limite supérieure.
recu_test(950)
# Finish
# recu_test(1500)
# RecursionError: maximum recursion depth exceeded in comparison
Notez que la valeur obtenue par sys.getrecursionlimit() n'est pas strictement le nombre maximal de récursions, mais la profondeur maximale de la pile de l'interpréteur Python, donc même si le nombre de récursions est légèrement inférieur à cette valeur, une erreur (RecursionError) sera levée.
La limite de récursion n'est pas la limite de récursion, mais la profondeur maximale de la pile de l'interpréteur python.
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
Modifier la limite de récursion : sys.setrecursionlimit()
La limite supérieure du nombre de récursions peut être modifiée par sys.setrecursionlimit(). La limite supérieure est spécifiée en argument.
Permet d'effectuer une récursion plus profonde.
sys.setrecursionlimit(2000)
print(sys.getrecursionlimit())
# 2000
recu_test(1500)
# Finish
Si la limite supérieure spécifiée est trop petite ou trop grande, une erreur se produit. Cette contrainte (limites supérieure et inférieure de la limite elle-même) varie en fonction de l'environnement.
La valeur maximale de la limite dépend de la plate-forme. Si vous avez besoin d'une récursion profonde, vous pouvez spécifier une valeur plus grande dans la plage supportée par la plate-forme, mais sachez que cette valeur provoquera un crash si elle est trop grande.
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
Le nombre maximal de récursions est également limité par la taille de la pile, comme expliqué ci-après.
Modifier la taille maximale de la pile : resource.setrlimit()
Même si une grande valeur est définie dans sys.setrecursionlimit(), elle peut ne pas être exécutée si le nombre de récursions est important. Une erreur de segmentation se produit comme suit.
sys.setrecursionlimit(10 ** 9)
print(sys.getrecursionlimit())
# 1000000000
recu_test(10 ** 4)
# Finish
# recu_test(10 ** 5)
# Segmentation fault
En Python, le module de ressources de la bibliothèque standard peut être utilisé pour modifier la taille maximale de la pile. Toutefois, le module de ressources est un module spécifique à Unix et ne peut être utilisé sous Windows.
- Unix Specific Services — Python 3.10.0 Documentation
- resource — Resource usage information — Python 3.10.0 Documentation
Avec resource.getrlimit(), vous pouvez obtenir la limite de la ressource spécifiée dans l'argument sous la forme d'un tuple de (soft limit, hard limit). Ici, nous spécifions resource.RLIMIT_STACK comme ressource, qui représente la taille maximale de la pile d'appels du processus actuel.
- 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)
Dans l'exemple, la limite douce est de 8388608 (8388608 B = 8192 KB = 8 MB) et la limite dure est -1 (illimité).
Vous pouvez modifier la limite de la ressource avec resource.setrlimit(). Ici, la limite souple est également fixée à -1 (aucune limite). Vous pouvez également utiliser la constante resource.RLIM_INFINIT pour représenter la limite illimitée.
La récursion profonde, qui ne pouvait pas être exécutée en raison d'un défaut de segmentation avant le changement de taille de la pile, peut maintenant être exécutée.
resource.setrlimit(resource.RLIMIT_STACK, (-1, -1))
print(resource.getrlimit(resource.RLIMIT_STACK))
# (-1, -1)
recu_test(10 ** 5)
# Finish
Ici, la limite souple est fixée à -1 (aucune limite) pour une expérience simple, mais en réalité, il serait plus sûr de la limiter à une valeur appropriée.
En outre, lorsque j'ai essayé de définir une limite logicielle illimitée sur mon mac également, l'erreur suivante s'est produite.ValueError: not allowed to raise maximum limit
L'exécution du script avec sudo n'a pas aidé. Il est peut-être restreint par le système.
Un processus avec l'UID effectif d'un superutilisateur peut demander toute limite raisonnable, y compris aucune limite.
Toutefois, une demande qui dépasse la limite imposée par le système entraînera toujours une ValueError.
resource.setrlimit() — Resource usage information — Python 3.10.0 Documentation
Windows ne dispose pas d'un module de ressources, et Mac n'a pas pu modifier la taille maximale de la pile en raison des limitations du système. Si nous pouvons augmenter la taille de la pile par un moyen quelconque, nous devrions être en mesure de résoudre le défaut de segmentation, mais nous n'avons pas été en mesure de le confirmer.