\makeatletter
\@ifundefined{complet}
{\documentclass[10pt]{report}
\title{Python}
\newcommand{\categorie}{Python}
\input{latex_entete_perso}

\begin{document} %Cours

\setcounter{chapter}{16}
% xelatex --shell-escape cours_python
}
{}
\makeatother

\IfFileExists{type_simple.png}{}{\write18{wget https://doc.infoforall.fr/activite/python/images/tableau/type_simple.png}}

\IfFileExists{type_construit.png}{}{\write18{wget https://doc.infoforall.fr/activite/python/images/tableau/type_construit.png}}

\IfFileExists{armoire_de_boites.png}{}{\write18{wget https://doc.infoforall.fr/activite/python/images/variables/armoire_de_boites.png}}

\IfFileExists{liaison_mot_contenus.png}{}{\write18{wget https://doc.infoforall.fr/activite/python/images/variables/liaison_mot_contenus.png}}

\IfFileExists{mm_principe.png}{}{\write18{wget https://doc.infoforall.fr/activite/python/images/dictionnaire/mm_principe.png}}

\IfFileExists{string_principe.png}{}{\write18{wget https://doc.infoforall.fr/activite/python/images/string/string_principe.png}}

\IfFileExists{tableau_principe.png}{}{\write18{wget https://doc.infoforall.fr/activite/python/images/tableau/tableau_principe.png}}

\IfFileExists{tuple_principe.png}{}{\write18{wget https://doc.infoforall.fr/activite/python/images/tuple/tuple_principe.png}}

\chapter{Boucles non bornées}





\section{Rappel préalable : le module random \small{Voir Variables Python 6.3.6}}



\section{Boucle non bornée tant que / while}

\begin{multicols}{2}


\subsection{Rappels \small{Introduction Python 1.4.11}}


\subsection{Bornée ou non bornée}

\begin{itemize}

\item Si on connait à l'avance le nombre de fois où on va devoir agir, on peut utiliser une boucle POUR.

\gras{La boucle POUR est une boucle bornée.}

\item Si on ne peut pas savoir à l'avance le nombre de fois où on va devoir agir, on utilise une boucle TANT QUE. 

C'est la condition de poursuite fournie qui va permettre de faire le choix de continuer ou pas. 

\item Si l'action peut potentiellement se dérouler à l'infini, il faut utiliser une boucle TANT QUE.

\gras{C'est pour cela que la boucle TANT est une boucle non bornée.}

\end{itemize}

Avec l'aléatoire, on a donc souvent du TANT QUE.


\subsection{Première évaluation de la condition}

\gras{Les variables nécessaires à l'évaluation du TANT QUE doivent toutes être définies avant la ligne du TANT QUE.}

Si la condition est basée sur une variable qui est calculée dans le bloc de la boucle elle-même, comment faire ? Initialiser cette variable avec une "fausse première valeur" de façon à rentrer dans la boucle au départ.

\gras{Exemple :} en ligne 7, on place 0 dans total, ce qui permet de valider la condition de poursuite : le total est inférieur à 16.

\begin{minted}[linenos=true, bgcolor=lightgray, tabsize=4, gobble=0, fontfamily=courier, fontsize=\small, xleftmargin=20pt, xrightmargin=5pt]{python}
import random
 
def de(nb):
    return random.randint(1, nb)
 
total = 0
 
while total < 16:
    total = de(6) + de(6) + de(6)
    print(total)
 
print(f"Le total est {total}")
\end{minted} 

\subsection{Condition d'arrêt ou de poursuite}

\fo{False} est la valeur complémentaire de \fo{True}. On passe de l'une à l'autre à l'aide du mot-clé \fo{not}.

\paragraph{A - Lien entre poursuite et arrêt} Pour résoudre un problème avec un TANT QUE, on utilise une condition de \fo{poursuite}.

\begin{minted}{python}
while poursuite:
    agir()
\end{minted} 

On tombe parfois plutôt sur une condition d'arrêt de la boucle... Comment faire alors ? C'est facile : on trouve la condition de \fo{poursuite} en inversant la condition d'arrêt avec \fo{not}.

\begin{itemize}

\item Si \fo{poursuite} est \fo{True}, c'est que \fo{arret} est \fo{False}.
\item Si \fo{poursuite} est \fo{False}, c'est que \fo{arret} est \fo{True}.

\end{itemize}




\paragraph{B - Deux écritures de la boucle TANT QUE} Pour décrire un même TANT QUE, on a donc deux possibilités d'écriture :

\begin{itemize}

\item Si vous connaissez la condition de \fo{poursuite} de la boucle :

\item Si vous connaissez la condition d'\fo{arret} de la boucle :

\begin{multicols}{2}
\begin{minted}{python}
while poursuite:
    agir()
while not arret:
    agir()
\end{minted} 
\end{multicols}

\end{itemize}


\paragraph{C - Exemple} Dire qu'on continue tant qu'on a moins de 2000 euros : 

\begin{multicols}{2}
\begin{minted}{python}
# version poursuite
while argent < 2000:      

# version arrêt
while not argent >= 2000: 
\end{minted} 
\end{multicols}


\paragraph{D - Cas typique qui cause des erreurs} :

\begin{itemize}

\item L'opérateur complémentaire de > est <=

\item L'opérateur complémentaire de >= est <

\end{itemize}




\subsection{Boucle infinie}

Pour créer une boucle qui ne s'arrête jamais, on choisit une condition de poursuite qui ne pourra jamais être évaluée à \fo{False} : \fo{True} !

\begin{minted}{python}
while True:
    faire_un_truc()
    faire_un_autre_truc()
\end{minted} 

La condition de poursuite étant juste \fo{True}, on va donc effectuer L2-L3 à l'infini.

Ce bouclage peut être voulu (comme sur un système embarqué qui ne doit jamais arrêter son programme) ou involontaire. Si c'est involontaire, c'est le drame car on ne pourra pas prendre la main à moins de stopper le programme.


\end{multicols}

\section{Exemple d'interaction}

\begin{minted}[linenos=true, bgcolor=lightgray, tabsize=4, gobble=0, fontfamily=courier, fontsize=\small, xleftmargin=20pt, xrightmargin=5pt]{python}
import random 
MINI = 0
MAXI = 100
 
def affichage(m, p):
    if m != p:
        if p > m:
            print("Raté, trop grand")
        else:
            print("Raté, trop petit")       
    else:
        print("Bien vu !")
 
mystere = random.randint(MINI, MAXI)
proposition = -1 
while not proposition == mystere:
    proposition = input("A votre avis ? ")
    proposition = int(proposition)
    affichage(mystere, proposition)
print("Vous avez trouvé !")
\end{minted} 


\section{Transformation d'une boucle en l'autre}

\begin{multicols}{2}

\subsection{Transformer un POUR en TANT QUE}

On peut remplacer les \fo{for} par des \fo{while}. La version \fo{while} est plus complexe puisqu'on doit écrire ce que le \fo{for} réalise en sous-main : initialiser la variable \fo{x},  transformer \fo{x in range(n+1)} en condition de poursuite \fo{x < n+1}, incrémenter la variable \fo{x} alors que c'est fait automatiquemnet avec \fo{for}.

\begin{minted}[linenos=true, bgcolor=lightgray, tabsize=4, gobble=0, fontfamily=courier, fontsize=\small, xleftmargin=20pt, xrightmargin=5pt]{python}
def somme_v1(n:int) -> int:
    """Renvoie la somme de 
    1 + 2 + 3... jusqu'à n."""
    reponse = 0
    for x in range(n+1): # on a donc x < n+1
        reponse = reponse + x
    return reponse
 
def somme_v2(n:int) -> int:
    """Renvoie la somme de 
    1 + 2 + 3... jusqu'à n."""
    reponse = 0
    x = 0
    while x < n+1:
        reponse = reponse + x
        x = x + 1
    return reponse
\end{minted}




\subsection{Transformer un POUR en TANT QUE}


\subsubsection{A - Cas des fonctions} 

Puisqu'on sort définitivement de la fonction une fois qu'on rencontre un \fo{return}, on peut interrompre un POUR à l'intérieur d'une fonction.

On peut donc parfois programmer une boucle non bornée en utilisant un for associé à return plutôt que d'utiliser directement un while.

Exemple : deux versions d'une fonction qui renvoie le premier mot de plus de 5 lettres trouvés dans une phrase.


\begin{minted}[linenos=true, bgcolor=lightgray, tabsize=4, gobble=0, fontfamily=courier, fontsize=\small, xleftmargin=20pt, xrightmargin=5pt]{python}
def premier_mot_v1(phrase):
    """Renvoie le premier mot de 
    plus de 5 lettres de la phrase,
    un str NON VIDE"""
    t = phrase.split(" ")
    i = 0
    while len(t[i]) < 5:
        i = i + 1
    if  i < len(t):
        return t[i]
 
def premier_mot_v2(phrase):
    """Renvoie le premier mot de 
    plus de 5 lettres de la phrase,
    un str NON VIDE"""
    t = phrase.split(" ")
    for i in range(len(t)):
        if len(t[i]) >= 5:
            return t[i]
\end{minted}




\subsubsection{B - Est-ce malin de faire cela ?}

Tout dépend du point de vue.

AVANTAGE du \fo{for+return}: en terme de programmation, on doit noter moins de choses en utilisant un \fo{for} associé à \fo{return}.

DESAVANTAGE du \fo{for+return} : cela crée une fonction qui possède deux sorties : n'oubliez pas que si Python ne rencontre pas le return de la ligne 8, on sortira de la fonction comme si vous aviez tapé return None. Deux sorties. Algorithmiquement, c'est donc plutôt sale.

\subsubsection{C - Pas de remplacement possible pour la boucle infinie}

Pour remplacer le \fo{fwhile} par un \fo{for}, il faut qu'il existe un nombre maximal de fois où on réalise la boucle. Si ce nombre n'existe pas, c'est à dire qu'il est possible de tourner à l'infini sans jamais sortir, il est bien entendu impossible de remplacer le TANT par un POUR équivalent.

\subsubsection{D - Hors d'une fonction ?}

\gras{Ne pas utiliser en NSI}

A titre d'exemple, voici un programme qui permet de stocker dans \fo{mot} le premier de 5 lettres ou plus, s'il existe.
 	
\begin{minted}[linenos=true, bgcolor=lightgray, tabsize=4, gobble=0, fontfamily=courier, fontsize=\small, xleftmargin=20pt, xrightmargin=5pt]{python}
phrase = """Phrase permettant 
de réaliser un exemple"""
mot = None
t = phrase.split(" ")
for i in range(len(t)):
    if len(t[i]) >= 5:
        mot = t[i]
        break
\end{minted}

\subsection{Conclusion : BORNEE ou NON BORNEE}

Avant de programmer une boucle, il convient de se demander si on a affaire à une boucle bornée ou une boucle non bornée car cela évitera de partir dans la mauvaise direction.

- Boucle bornée : \fo{for}

- Boucle non bornée sans nombre maximum de tours prévisible : \fo{while}

- Boucle non bornée avec un nombre maximum prévisible : \fo{while} ou \fo{for+return}

\end{multicols}


\input{licence}

\makeatletter
\@ifundefined{complet}
{\end{document}}

{}
\makeatother

