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 :

Un problème lié à la récursivité ? [Python 3.X]


Sujet :

Python

  1. #1
    Futur Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2022
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gers (Midi Pyrénées)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Août 2022
    Messages : 8
    Points : 7
    Points
    7
    Par défaut Un problème lié à la récursivité ?
    Bonjour,
    j'ai voulu utiliser la récursivité pour un code très simple, il s'agit d'une fonction pour la saisie d'une lettre (avec contrôle qu'il y a bien une seule lettre et que c'est une lettre sans accent)
    Problème de mon code : le contrôle fonctionne mais le retour de la lettre saisie ne fonctionne que si je mets directement une valeur valide, si je saisie d'abord une entrée non valide ('AA' ou 'è' par exemple), la fonction ne renvoie rien quand je saisis un caractère valide.

    Pour bien expliquer, j'ai écrit deux fonctions avec ou sans récursivité que je teste ci dessous.
    Si quelqu'un a une explication sur ce que je fais mal, je suis preneur,
    Merci


    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
    essai de la fonction SANS récursivité
    saisissez une lettre : AA
    erreur, vous ne devez saisir qu'une seule lettre
    saisissez une lettre : è
    erreur : vous devez saisir une lettre (sans accent ou cédille)
    saisissez une lettre : d
    D 
     
    1er essai de la fonction AVEC récursivité
    saisissez une lettre : AA
    erreur, vous ne devez saisir qu'une seule lettre
    saisissez une lettre : è
    erreur : vous devez saisir une lettre (sans accent ou cédille)
    saisissez une lettre : d
    None 
     
    2nd essai de la fonction AVEC récursivité
    saisissez une lettre : d
    D
    lignes 1 à 7 Fonctionnement normal de la fonction sans récursivité avec le retour de la lettre 'D' ligne 7
    lignes 9 à 15 même test avec la fonction récursive mais erreur elle renvoie 'NONE' ligne 15
    ligne 17 à 19 pourtant elle revoie bien une lettre si je saisie tout de suite une lettre valide




    mon code
    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
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    def saisir_une_lettre():
        '''renvoie une lettre entre A et Z'''
     
        entreeInvalide = True
        while entreeInvalide :
            entree = input("saisissez une lettre : ")
            # contrôle de la longueur de la chaîne saisie
            if len(entree) != 1:
                print('erreur, vous ne devez saisir qu\'une seule lettre')
            else:
                # passage en majuscule
                entree = entree.upper()
                # contrôle que le caractère est bien entre A et Z (ord 65-90)
                if not (ord(entree) > 64 and ord(entree) < 91):
                    print('erreur : vous devez saisir une lettre (sans accent ou cédille)')
                else:
                    entreeInvalide = False
                    return entree
     
    def saisir_une_lettre_recursive():
        '''renvoie une lettre entre A et Z
        Inachevé, le code fonctionne si on saisit une lettre valide du premier coup
         mais mais aucun retour pour une entrée valide après une entrée invalide avant ???'''
        entree = input("saisissez une lettre : ")
        #contrôle de la longueur de la chaîne saisie
        if len(entree) !=1:
            print('erreur, vous ne devez saisir qu\'une seule lettre')
            saisir_une_lettre_recursive()
        else:
            # passage en majuscule
            entree = entree.upper()
            # contrôle que le caractère est bien entre A et Z (ord 65-90)
            if not(ord(entree)>64 and ord(entree)< 91) :
                print('erreur : vous devez saisir une lettre (sans accent ou cédille)')
                saisir_une_lettre_recursive()
            else :
                return entree
     
     
    # démo fonction
    print('essai de la fonction SANS récursivité')
    lettre = saisir_une_lettre()
    print(lettre, '\n')
     
     
    print('1er essai de la fonction AVEC récursivité')
    lettre = saisir_une_lettre_recursive()
    print(lettre, '\n')
     
     
    print('2nd essai de la fonction AVEC récursivité')
    lettre = saisir_une_lettre_recursive()
    print(lettre, '\n')
    Ubuntu 22 pycharm python 3.10

  2. #2
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Bonjour
    Citation Envoyé par BertrandMS Voir le message
    Si quelqu'un a une explication sur ce que je fais mal, je suis preneur,
    Les appels à la fonction récursive ne retournent rien. La récursion finale retourne bien la lettre mais cette lettre n'est pas récupérée par les appels supérieurs.
    Bref rajoute return à chaque appel de saisir_une_lettre_recursive().

    Accessoirement if not (ord(entree) > 64 and ord(entree) < 91) peut parfaitement s'écrire if not (entree >= 'A' and entree <= 'Z') (ça me semble bizarrement plus clair) voire ensuite if not ('A' <= entree <= 'Z').

    PS: j'ose espérer que c'est juste un test d'apprentissage et que tu ne comptes pas remplacer les boucles de validation par de la récursivité...

  3. #3
    Futur Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2022
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gers (Midi Pyrénées)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Août 2022
    Messages : 8
    Points : 7
    Points
    7
    Par défaut Super merci
    Ok, çà marche en rappelant la fonction après un return.
    Et Merci pour le conseil de tester directement sur l'ordre des caractères ; effectivement beaucoup plus lisible

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    def saisir_une_lettre_recursive():
        '''renvoie une lettre entre A et Z saisie au clavier'''
        entree = input("saisissez une lettre : ")
        #contrôle de la longueur de la chaîne saisie
        if len(entree) !=1:
            print('erreur, vous ne devez saisir qu\'une seule lettre')
            return saisir_une_lettre_recursive()
     
        else:
            # passage en majuscule
            entree = entree.upper()
            if not('A' <= entree <= 'Z') :
                print('erreur : vous devez saisir une lettre (sans accent ou cédille)')
                return saisir_une_lettre_recursive()

  4. #4
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par BertrandMS Voir le message
    Ok, çà marche en rappelant la fonction après un return.
    Si on sort sur un "if", pas besoin de "else". On gagne en indentation (et j'irai même dire "en lisibilité")...

    Code python : 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
    def saisir_une_lettre_recursive():
    	'''renvoie une lettre entre A et Z
            Inachevé, le code fonctionne si on saisit une lettre valide du premier coup
             mais mais aucun retour pour une entrée valide après une entrée invalide avant ???'''
    	entree = input("saisissez une lettre : ")
    	#contrôle de la longueur de la chaîne saisie
    	if len(entree) !=1:
    		print('erreur, vous ne devez saisir qu\'une seule lettre')
    		return saisir_une_lettre_recursive()
    	# if
     
    	# passage en majuscule
    	entree = entree.upper()
    	# contrôle que le caractère est bien entre A et Z (ord 65-90)
    	if not('A' <= entree <= 'Z') :
    		print('erreur : vous devez saisir une lettre (sans accent ou cédille)')
    		return saisir_une_lettre_recursive()
    	# if
     
    	return entree
    # saisir_une_lettre_recursive()

  5. #5
    Futur Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2022
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gers (Midi Pyrénées)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Août 2022
    Messages : 8
    Points : 7
    Points
    7
    Par défaut
    Citation Envoyé par Sve@r Voir le message
    Bonjour

    PS: j'ose espérer que c'est juste un test d'apprentissage et que tu ne comptes pas remplacer les boucles de validation par de la récursivité...
    Oui, c'est bien un test d'apprentissage, mais en quoi il vaut mieux que j'évite cette technique ?

  6. #6
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Déjà, dans Python, la profondeur de récursion est limitée à 1000. Donc entre 1001 mauvaises saisies et ton code plante.

    Mais surtout (et c'est le pourquoi de cette limitation) la récursivité c'est ultra lourd. Ce qui se traduit pour le programmeur par un simple "je délègue le travail à mon fils et j'attends benoîtement que ça me revienne tout cuit" se traduit, dans le processeur, par une mise en attente (en mémoire), création d'un contexte de travail dédié à l'instance récursive, et ce autant de fois qu'il y a d'appels.

    Essaye ce code...
    Code python : 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
    #!/usr/bin/env python3
     
    def fibonacci_r(n):
    	if n < 2: return (1, 1)[n]
    	return fibonacci_r(n-2) + fibonacci_r(n-1)
     
    def fibonacci_i(n):
    	res=(1, 1)
    	if n < 2: return res[n]
    	while n > 1:
    		res=(res[1], res[0] + res[1])
    		n-=1
    	return res[-1]
     
    print(fibonacci_i(40))
    print(fibonacci_r(40))
    ... et compare le temps d'attente entre le premier appel et le second.

  7. #7
    Futur Membre du Club
    Homme Profil pro
    Enseignant
    Inscrit en
    Août 2022
    Messages
    8
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Gers (Midi Pyrénées)

    Informations professionnelles :
    Activité : Enseignant

    Informations forums :
    Inscription : Août 2022
    Messages : 8
    Points : 7
    Points
    7
    Par défaut
    Ok, merci pour les explications. J'ai testé, c'est éloquent. C'est dans le bouquin de Vincent Le Goff qu'il est proposé de faire ce genre de contrôle en récursif. Il parle bien de l'inefficacité de la récursivité dans certains cas mais que cela dépend.

    Merci pour ces précisions. Je vais rester sur des boucles simples.

  8. #8
    Expert éminent sénior
    Avatar de Sve@r
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Février 2006
    Messages
    12 721
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Oise (Picardie)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Février 2006
    Messages : 12 721
    Points : 31 044
    Points
    31 044
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par BertrandMS Voir le message
    mais que cela dépend.
    Oui effectivement il existe des cas où la récursivité ne coûte rien: c'est dans les cas de récursivité dite "terminale". C'est quand le père n'attend rien de son fils. Dans ce cas, pas besoin d'empiler quoi que ce soit. Chaque appel remplace le précédent...
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    def affiche_lettre(n):
    	print(n[0])
    	if len(n) == 1: return
    	affiche_lettre(n[1:])
     
    affiche_lettre("hello")

    Mais déjà avoir cette possibilité est bien bien rare... et surtout ça n'enlève pas la limitation des 1000 appels récursifs !
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    >>> affiche_lettre("x" * 1001)
    RecursionError: maximum recursion depth exceeded while calling a Python object

    Le récursif: on ne l'utilise que si on ne peut pas faire autrement !
    Code python : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    def affiche_lettre(n):
    	for x in n: print(x)

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. probleme d'execution un petit problme
    Par naoufal_bago dans le forum Débuter avec Java
    Réponses: 3
    Dernier message: 04/03/2008, 00h54
  2. Problme impression d'état
    Par travanca dans le forum IHM
    Réponses: 2
    Dernier message: 02/01/2008, 12h47
  3. problme de multi thread
    Par L4BiN dans le forum Concurrence et multi-thread
    Réponses: 22
    Dernier message: 25/04/2007, 16h47
  4. problme mot de passe sur feuille
    Par faby75 dans le forum Excel
    Réponses: 1
    Dernier message: 29/03/2007, 11h17
  5. [MySQL] Problme de variables dans requete
    Par eown dans le forum PHP & Base de données
    Réponses: 6
    Dernier message: 11/04/2006, 17h05

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