Contexte:
Il arrive parfois d'avoir l'erreur: RecursionError: maximum recursion depth exceeded.
Il s'agit généralement d'un bug mais pas toujours, parfois il faudrait pousser cette limite plus loin quand on n'arrive pas à transformer notre code en code itératif.
Plus particulièrement, si le nombre de couches de récursion dépend du volume de donnée traité, il faut pouvoir changer cette limite dynamiquement.
C'est pourquoi j'ai écrit le décorateur suivant:
Il fonctionne environ, je dit environ car il dépasse de beaucoup le nombre de récursion que l'on imagine.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35 import copy import sys import logging def _improve_recursion_decorateur(increment): """ permet d'eviter les problemes de limites de recursion car si il y a un probleme, la limite est augmentee de 'increment' """ assert type(increment) is int, "'increment' doit etre un entier, '%s' n'est pas un entier, c'est un %s." % (increment, type(increment)) assert increment > 0, "'increment' doit etre strictement positif, ce n'est pas le cas de %d." % increment def decorateur(fonction_a_executer): def fonction_modifiee(*args, **kwargs): args_copie = copy.copy(args) kwargs_copie = copy.copy(kwargs) while 1: try: return fonction_a_executer(*args_copie, **kwargs_copie) except RecursionError as e: if sys.getrecursionlimit() >= 10000: # si on a deja depasse une limite raisonable de recursion raise e from e # on est surement dans une boucle infinie, donc on ne s'entete pas try: avant = sys.getrecursionlimit() sys.setrecursionlimit(min(10000, avant+increment)) # si il y a trop de recursions par exemple a + b + c - g * 3 + ... except Exception as e: raise e from e logging.warning("Recursion limit increased from %d to %d." % (avant, sys.getrecursionlimit())) continue except Exception as e: raise e from e return fonction_modifiee return decorateur
Un petit exemple:
Pourquoi il va jusqu’à 6000 alors qu'il n'y a qu'environ 2000 "boucles"!
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 >>> @ _improve_recursion_decorateur(20) ... def f(n): ... return f(n-1) if n else "fini" ... >>> f(2000) WARNING:root:Recursion limit increased from 1000 to 1020. WARNING:root:Recursion limit increased from 1020 to 1040. WARNING:root:Recursion limit increased from 1040 to 1060. WARNING:root:Recursion limit increased from 1060 to 1080. ... WARNING:root:Recursion limit increased from 5960 to 5980. WARNING:root:Recursion limit increased from 5980 to 6000. WARNING:root:Recursion limit increased from 6000 to 6020. 'fini' >>>![]()
Partager