IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

décorateur, recursion, explosion de la pile


Sujet :

Python

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre éprouvé
    Homme Profil pro
    Vagabong étudiant en annalyse du signal.
    Inscrit en
    Avril 2019
    Messages
    130
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 26
    Localisation : France, Isère (Rhône Alpes)

    Informations professionnelles :
    Activité : Vagabong étudiant en annalyse du signal.
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Avril 2019
    Messages : 130
    Par défaut décorateur, recursion, explosion de la pile
    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:
    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
    Il fonctionne environ, je dit environ car il dépasse de beaucoup le nombre de récursion que l'on imagine.
    Un petit exemple:
    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'
    >>>
    Pourquoi il va jusqu’à 6000 alors qu'il n'y a qu'environ 2000 "boucles"!

  2. #2
    Expert éminent
    Homme Profil pro
    Architecte technique retraité
    Inscrit en
    Juin 2008
    Messages
    21 754
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Manche (Basse Normandie)

    Informations professionnelles :
    Activité : Architecte technique retraité
    Secteur : Industrie

    Informations forums :
    Inscription : Juin 2008
    Messages : 21 754
    Par défaut
    Salut,

    Citation Envoyé par robinechuca Voir le message
    Pourquoi il va jusqu’à 6000 alors qu'il n'y a qu'environ 2000 "boucles"!
    Vu que recursionlimit est détecté non pas en fonction du nombre d'appels récursifs mais en fonction du nombre d'appels de fonctions "en cours" et qu'un décorateur, c'est déjà la composition de 2 appels de fonctions, çà commence à incrémenter récursion limit arrivé à 500 appels à la fonction initiale et incrémenter de 20 ne permettra que 10 appels supplémentaires.

    Votre décorateur bouffe déjà la moitié de la capacité de la pile d'appels!

    - W
    Architectures post-modernes.
    Python sur DVP c'est aussi des FAQs, des cours et tutoriels

Discussions similaires

  1. Réponses: 31
    Dernier message: 06/07/2006, 14h35
  2. Créer des objets sur la pile ?
    Par Cornell dans le forum Langage
    Réponses: 8
    Dernier message: 03/03/2003, 11h47
  3. Etat de la pile sous Linux et Windows
    Par Bibouda dans le forum x86 32-bits / 64-bits
    Réponses: 7
    Dernier message: 16/02/2003, 01h28
  4. La mémoire en Pmode et en Rmode - la pile
    Par le mage tophinus dans le forum Assembleur
    Réponses: 15
    Dernier message: 16/02/2003, 01h00
  5. [TASM] Déclarer le segment de pile
    Par cipher dans le forum x86 16-bits
    Réponses: 2
    Dernier message: 01/10/2002, 03h58

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo