Python pour PC* Daniel Lecouturier 2018 2019 - Orange

La page est créée Dominique Breton
 
CONTINUER À LIRE
Python pour PC* Daniel Lecouturier 2018 2019 - Orange
Python pour PC*

   Daniel Lecouturier

      2018 - 2019
Python pour PC* Daniel Lecouturier 2018 2019 - Orange
Table des matières

1 Communiquer avec des fichiers                                                                                                                       4
  1.1 Chemin d’accès à un fichier ou un répertoire                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    4
      1.1.1 Nom . . . . . . . . . . . . . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    4
      1.1.2 Choix du répertoire d’enregistrement                        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    4
      1.1.3 slash, antislash . . . . . . . . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    5
  1.2 Ouverture de fichier . . . . . . . . . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    5
      1.2.1 En mode lecture . . . . . . . . . . .                        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    5
      1.2.2 En mode écriture . . . . . . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    5
  1.3 Modules . . . . . . . . . . . . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    6
      1.3.1 Différents modes d’importation . . .                        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    6
      1.3.2 Modules sys et os . . . . . . . . . .                        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    6
      1.3.3 Enregistrer ses propres modules . . .                        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    6

2 Ingéniérie numérique                                                                                                                             8
  2.1 Modules . . . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    8
       2.1.1 Présentation . . . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    8
       2.1.2 Alias d’importation usuels          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    9
  2.2 numpy . . . . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    9
       2.2.1 Tableaux . . . . . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .    9
       2.2.2 Vectorisation . . . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   11
       2.2.3 Constructeurs . . . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   11
       2.2.4 Vue et copie . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   11
       2.2.5 Sauvegarde . . . . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   12
  2.3 matplotlib . . . . . . . . . . . .         .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   13
       2.3.1 Syntaxe minimale . . . .            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   13
       2.3.2 Lignes de niveau . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   13
       2.3.3 Syntaxe enrichie . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   14
       2.3.4 Images . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   14
       2.3.5 3d . . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   15
  2.4 scipy . . . . . . . . . . . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   16
       2.4.1 Résoudre des équations .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   16
       2.4.2 Intégrer . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   16
       2.4.3 Résoudre une ODE . . . .           .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   17

3 Représentation binaire de données                                                                                                                19
  3.1 Entiers en base 2 . . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   19
  3.2 Entiers relatifs . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   20
  3.3 Flottants . . . . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   22
  3.4 Caractères . . . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   23
  3.5 Conclusion . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   25

                                                     1
Python pour PC* Daniel Lecouturier 2018 2019 - Orange
4 Fonctions                                                                                                                                          26
  4.1 Généralités . . . . . . . . . . . . . . . . .               .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   26
      4.1.1 En tête . . . . . . . . . . . . . . . .                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   26
      4.1.2 Valeur de retour . . . . . . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   26
  4.2 Portée des variables . . . . . . . . . . . . .                .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   27
      4.2.1 Nom de variable . . . . . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   27
      4.2.2 Variables globales . . . . . . . . . .                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   28
      4.2.3 Liaison dynamique . . . . . . . . .                      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   28
      4.2.4 Variables locales . . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   28
      4.2.5 Fonctions locales . . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   29
  4.3 Passage des arguments . . . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   30
      4.3.1 Passage par valeurs . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   30
      4.3.2 Fonction qui modifie ses arguments                       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   31
      4.3.3 Attention aux raccourcis . . . . . .                     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   32
      4.3.4 Valeurs par défaut . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   33
  4.4 Méthodes pour objets . . . . . . . . . . . .                  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   33

5 La structure de Pile                                                                                                                               34
  5.1 Structures de données . . . . . . . . . . .                   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   34
  5.2 La structure de pile . . . . . . . . . . . . .                 .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   34
  5.3 Implémentation minimaliste . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   35
  5.4 Implémentation par liste . . . . . . . . . .                  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   36
  5.5 Implémentation par tableau . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   37
  5.6 Implémentation par objet . . . . . . . . .                    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   38
       5.6.1 Par héritage de la structure de liste                  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   38
       5.6.2 Par chaı̂nage d’objets . . . . . . . .                  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   39

6 Récursivité                                                                                                                                      41
  6.1 Fonction récursive . . . . . . . . . . . . . . . . . .                            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   41
       6.1.1 Une fonction peut en appeler une autre . .                                  .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   41
       6.1.2 Une fonction récursive s’appelle elle-même                                .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   41
  6.2 Appels récursifs . . . . . . . . . . . . . . . . . . . .                          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   41
  6.3 Limitations . . . . . . . . . . . . . . . . . . . . . .                            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   42
  6.4 Caractéristiques . . . . . . . . . . . . . . . . . . . .                          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   42
  6.5 Code itératif ou récursif ? . . . . . . . . . . . . . .                          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   42

7 Algorithmes de tri                                                                                                                                 44
  7.1 Ressources en ligne . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   44
  7.2 Tri par dénombrement . . . . .        .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   44
  7.3 Tri par sélection . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   45
  7.4 Tri par insertion . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   46
  7.5 Tri par fusion (alias merge sort)      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   48
  7.6 Tri rapide (alias quicksort) . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   50

8 Bases de données                                                                                                                                  53
  8.1 Définitions . . . . . . . . . . . . . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   53
  8.2 Langage SQL . . . . . . . . . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   53
  8.3 Interface graphique . . . . . . . . .          .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   53
  8.4 Dialogue avec une base de données             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   54
      8.4.1 Casse . . . . . . . . . . . .            .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   54
      8.4.2 Administration . . . . . . .             .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   54

                                                     2
8.4.3 Opérations ensemblistes       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   55
    8.4.4 Projection . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   55
    8.4.5 Sélection . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   55
    8.4.6 Jointure symétrique . .       .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   55
    8.4.7 Alias . . . . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   56
    8.4.8 Agrégation . . . . . . .      .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   56
    8.4.9 Résumé . . . . . . . . .     .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   56
8.5 Base-jouet . . . . . . . . . . . .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   57
8.6 Vue sur les menus . . . . . . . .    .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   .   58

                                                 3
Chapitre 1

Communiquer avec des fichiers

1.1        Chemin d’accès à un fichier ou un répertoire
1.1.1       Nom
   Le nom seul du fichier dans une session PYTHON fait implicitement référence à un fichier
du répertoire courant. Pour connaı̂tre ce répertoire, taper cd dans le shell ou dans un script
(pas de print pour une fois...).
    import matplotlib.pyplot as plt
    import numpy as np
    from mpl_toolkits.mplot3d import Axes3D

    plt.close() #au cas où une figure serait active
    ax = Axes3D(plt.figure())
    X = np.linspace(-5, 5, 100)
    Y = np.linspace(-1.5, 1.5, 100)
    X, Y = np.meshgrid(X, Y)
    Z = -np.cos(X)+Y**2/2
    ax.plot_wireframe(X, Y, Z, rstride=10, cstride=10)
    plt.show()

    plt.savefig(’fildefer.png’)

    cd

    L’image est enregistrée sous le nom fildefer.png (l’extension .png précise l’encodage de
l’image) dans le répertoire indiqué en réponse à la commande cd.

1.1.2       Choix du répertoire d’enregistrement
   Il est possible de changer ce comportement pour enregistrer à un endroit choisi.

   • en indiquant le chemin complet, depuis la racine.

         plt.savefig(’C:/Users/daniel/python/graphiques/fildefer.png’)

   • en indiquant le chemin relatif, du répertoire courant à un sous-répertoire (c’est plus
     restrictif que la méthode précédente).
         #en supposant que C:/Users/daniel est le repertoire courant et que Python/graphiques
         est un sous-repertoire

         plt.savefig(’Python/graphiques/fildefer.png’)

                                                         4
• en changeant le répertoire courant avec le module os. On peut encore désigner l’empla-
     cement de ce nouveau répertoire par son chemin complet (depuis la racine), ou si c’est
     un sous-répertoire du répertoire courant, par le chemin relatif.
       import os

       print(os.getcwd()) #noter le print!
       os.chdir(’Python/graphiques’) #chemin relatif
       print(os.getcwd()) #verification
       plt.savefig(’fildefer.png’)

1.1.3     slash, antislash
    Le séparateur \ (antislash) utilisé par windows est un caractère spécial qui change l’in-
terprétation du caractère qui le suit. Par exemple \n désigne une fin de ligne.
Il est donc vivement recommandé de le remplacer par un slash / ou de le doubler ainsi \\
Python essaye de doubler les antislash, avec un bonheur inégal. Il vaut mieux s’en charger
soi-même. C’est la solution slash qui a été adoptée dans les exemples précédents.

1.2      Ouverture de fichier
1.2.1     En mode lecture
    #pour enregistrer la lecture de tout le fichier dans une chaine
    with open(’chemin’,’r’) as f:
        t = f.read()

    #pour enregistrer la lecture de la premiere ligne dans une chaine
    with open(’chemin’,’r’) as f:
        t = f.readline()

    #pour enregistrer la lecture de toutes les lignes dans une liste de chaines
    with open(’chemin’,’r’) as f:
        t = f.readlines()

   • Avec un argument dans read(), on contrôle le nombre de caractères lus.

   • Noter que la lecture est séquentielle : si vous venez d’exécuter, juste après l’ouver-
     ture, f.read(50), la lecture se poursuivra à partir du caractère suivant. Par exemple,
     f.readline() lira du cinquante-et-unième caracère jusqu’à la prochaine fin de ligne.

   • Si le fichier n’existe pas (à l’emplacement indiqué), PYTHON affiche un message d’erreur.

1.2.2     En mode écriture
    with open(’chemin’,’w’) as f:
        f.write(chaine)

    Il vaut mieux donner un nom de fichier qui n’existe pas encore (sinon, le contenu est pro-
gressivement effacé et remplacé par les caractères écrits). Là aussi, l’écriture est séquentielle
et reprend où elle s’est arrêtée (jusquà la fermeture du fichier, qui intervient quand le code
est aligné avec with, à la fin de l’indentation).

                                                       5
1.3      Modules
1.3.1     Différents modes d’importation
   Prenons l’exemple du module math. On ne le répétera jamais assez : l’instruction dir(math)
donne la liste des fonctions qu’il renferme, l’instruction help(math) documente chacune de
ces fonctions.

                     Table 1.1 – Différents modes d’importation d’un module

                            Mode d’importation             Appel de commande
                            import math                    math.cos(2)
                            import math as m               m.cos(2)
                            from math import cos           cos(2)
                            from math import *             tan(2)

    IMPORTANT : Les deux premières méthodes évitent les conflits de noms (par exemple,
de nombreux modules contiennent une fonction cos !) : c’est l’intérêt même de la notation ob-
jet. Il est donc conseillé de les privilégier. Les exemples qui suivront importeront les modules
utiles sous la première forme (sauf mention explicite).
    WARNING : Ce qui suit n’est absolument pas important...

1.3.2     Modules sys et os
    Ces modules contiennent de nombreuses fonctionnalités permettant d’interagir avec les
fichiers et le système d’exploitation. Ci-dessous quelques exemples.
    import os, sys

    dir(os) #pour avoir la liste de tous les objets de ce module
    dir(sys)

    os.getcwd() #pour conna^
                           ıtre le dossier de travail
    print(os.path.getsize("C:/users/daniel/fildefer.png")) #pour conna^
                                                                      ıtre la taille
     d’un fichier en octets

    print(sys.float_info)

1.3.3     Enregistrer ses propres modules
   https://docs.python.org/3.5/tutorial/modules.html
Un fichier où sont définies un certain nombre de fonctions (ou de classes) peut être employé
comme un module. Voici la marche à suivre :

   • Écrire et enregistrer un fichier PYTHON (en notant le chemin menant au répertoire
     choisi), par exemple dans le répertoire (créé antérieurement) C:/Users/daniel/opus_mei

                                                       6
def safe_path(chemin):
       """Remplace les antislash \ par des slashs/. Echec avec les caractères spéciaux, comme \a, \b etc..."""
       new = ""
       for c in chemin:
           if c == ’\\’: #noter le doublement de l’antislash
                c =’/’
           new += c
       return(new)

   if __name__=="__main__":
       print(safe_path(’D:\Daniel\python\graphiques’))

  Noter la documentation et le test final (prévu pour n’être exécuté que si le script est
  actif : il ne le sera pas si le fichier est importé dans un autre script).

• prendre connaissance du PYTHONPATH (liste des répertoires où les modules sont re-
  cherchés.
   import sys

   print(sys.path) #pas de parenthese, c’est un attribut de l’objet sys

• si le répertoire choisi où est enregistré safe_path n’y figure pas, l’ajouter.

   sys.path.append(’C:/Users/daniel/opus_mei’)

• on peut alors importer ce module comme n’importe quel module présent dans l’environ-
  nement (ici Pyzo), utiliser ses fonctions, consulter la documentation qu’on a prévue...
   from opus_mei import safe_path

   help(safe_path)

   print(safe_path(’E:\premiercours\TP1’))

  L’extension de PYTHONPATH n’est pas permanente, elle ne dure que le temps de la session
  ouverte.

                                                    7
Chapitre 2

Ingéniérie numérique

2.1     Modules
2.1.1    Présentation
numpy permet d’utiliser des tableaux de grande taille avec des procédures optimisées.
   http://www.numpy.org/

matplotlib permet toutes sortes de représentations graphiques.
    http://matplotlib.org/

scipy fournit des routines de résolution numérique approchée d’équations.
     http://docs.scipy.org/doc/

Ces trois modules s’utilisent conjointement : les tableaux de numpy servent de conteneur
pour des données dont certaines peuvent être produites par scipy et être visualisées avec
matplotlib. Voir le paragraphe 2.4.3 pour un exemple conséquent qui illustre la démarche
générale :

   • on balaye l’intervalle choisi par la commande linspace qui produit un tableau t

   • on applique les fonctions choisies, ce qui produit des tableaux de même taille que t : x,
     y etc...

   • on peut extraire une partie d’un tableau par les techniques de slicing.

Pour consulter la documentation que le concours Centrale met à votre disposition (et qui fixe
le noyau des fonctions dont vous devez connaı̂tre l’existence) :
http://www.concours-centrale-supelec.fr/CentraleSupelec/SujetsOral/PC
et les rubriques :

   • Calcul matriciel

   • Réalisation de tracés

   • Analyse numérique

   • Polynômes

   • Probabilités

                                              8
Table 2.1 – exemples d’importation

 import numpy as np
 import matplotlib.pyplot as plt                           module de réprésentation graphique
 import scipy.optimize as optim                            module de résolution approchée d’équations
 from scipy.integrate import quad                          commande d’intégration approchée
 from scipy.integrate import odeint                        commande de résolution approchée d’ODE
 from numpy.polynomial import Polynomial                   cf Python-polynomes.pdf de Centrale
 import numpy.random as rd                                 cf Python-random.pdf de Centrale

2.1.2     Alias d’importation usuels
   Consulter la table 8.5 et le site de Centrale (ci-dessus).

2.2      numpy
   Obtenir de l’aide : consulter http://docs.scipy.org/doc/numpy/reference/generated/
numpy.info.html#numpy.info et aussi http://docs.scipy.org/doc/numpy/reference/generated/
numpy.lookfor.html#numpy.lookfor
   Quand on connaı̂t le nom de la fonction, par exemple load du module numpy précédemment
importé 1 sous l’alias np, la commande help(np.load) donne accès à sa documentation.

2.2.1     Tableaux
    Le terme tableau sous-entend ici : tableau du module numpy donc les données doivent
toutes être du même type.
Ce type est soit déclaré à la création en même temps que la taille du tableau 2 , soit automa-
tiquement déterminé par PYTHON en cas de création explicite (en général pour des tableaux
de petite taille).
    import numpy as np

    tf = np.zeros(10, dtype=np.float)
    ti = np.array([1,2,3])
    print(tf.dtype, ti.dtype)

    Les types reconnus par numpy (voir http://docs.scipy.org/doc/numpy/user/basics.
types.html) sont rassemblés dans un tableau dont il suffit de connaı̂tre l’existence, comme
pour de nombreuses données techniques sur Python. Plusieurs formats de nombres entiers,
flottants, complexes et les booléens.

  1. Il faut que le module soit importé pour consulter l’aide sur une de ses fonctions.
  2. par défaut, c’est le type float

                                                       9
Table 2.2 – Types de données

Data type  Description
bool       Boolean (True or False) stored as a byte
int        Default integer type (same as C long ; normally
           either int64 or int32)
intc       Identical to C int (normally int32 or int64)
intp       Integer used for indexing (same as C ssize t ; nor-
           mally either int32 or int64)
int8       Byte (-128 to 127)
int16      Integer (-32768 to 32767)
int32      Integer (-2147483648 to 2147483647)
int64      Integer          (-9223372036854775808              to
           9223372036854775807)
uint8      Unsigned integer (0 to 255)
uint16     Unsigned integer (0 to 65535)
uint32     Unsigned integer (0 to 4294967295)
uint64     Unsigned integer (0 to 18446744073709551615)
float      Shorthand for float64
float16    Half precision float : sign bit, 5 bits exponent, 10
           bits mantissa
float32    Single precision float : sign bit, 8 bits exponent, 23
           bits mantissa
float64    Double precision float : sign bit, 11 bits exponent,
           52 bits mantissa
complex    Shorthand for complex128
complex64 Complex number, represented by two 32-bit floats
           (real and imaginary components)
complex128 Complex number, represented by two 64-bit floats
           (real and imaginary components)

                               10
2.2.2     Vectorisation
Principe et avantages
     Le module numpy fournit des opérateurs et des fonctions qui s’appliquent élément par
élément de tableaux de même forme, rendant inutile l’écriture de boucles (code plus com-
pact) et débouchant sur un traitement interne beaucoup plus rapide (code plus efficace).
import numpy as np
from time import clock
import math

N = 10**6
t = np.linspace(0,1,N)
r = np.zeros(N)
debut = clock()
for i in range(N):
    r[i] = np.exp(t[i]) #contresens!!!
print(clock() - debut)

debut = clock()
for i in range(N):
    r[i] = math.exp(t[i])
print(clock() - debut)

debut = clock()
r = np.exp(t)
print(clock() - debut)

Opérateurs
   Les opérateurs sont +, -, *, /, **

Fonctions
   La liste des fonctions usuelles peut être consultée à http://docs.scipy.org/doc/numpy/
reference/ufuncs.html#available-ufuncs

2.2.3     Constructeurs
   Voir http://docs.scipy.org/doc/numpy/reference/routines.array-creation.html

    Comme toujours, si le module n’a pas importé toutes les fonctions (from numpy import *
à proscrire) mais avec import numpy as np, les fonctions doivent être préfixées par np.

2.2.4     Vue et copie
   Deux différences essentielles avec les listes de Python :

   • les données sont typées, et certains types ne peuvent être affectés dans un tableau numpy
     (les caractères ou les séquences que sont les listes, chaı̂nes, tuples...)
     Par conséquent, si c’est nécessaire et possible, certaines données sont converties auto-
     matiquement : par exemple, si t = np.zeros(3, float), l’instruction t[0] = 3 conver-
     tit l’entier 3 en nombre flottant 3. avant l’affectation.
     Notamment sur les entiers typés de numpy, certaines limitations peuvent surprendre,
     comme les dépassements de capacité :

                                               11
Table 2.3 – Routines sur les tableaux

        Nom                 Action                        Syntaxe
        array(data)         type autodéterminé          x = array([0., 1., 2.])
        array(data, d)      data et type déclarés       y = array([0, 1, 2],float)
        linspace(d, f, n)   n données entre d            t = linspace(0, 1, 3)
                            et f régulièrement es-
                            pacées
        meshgrid(x, y, ...) réseau          produit      tt, xx = meshgrid(t, x)
                            cartésien des vec-
                            teurs x, y, ...
        zeros(s, d)         initialisation à 0 de        u = ones([2, 2], int)
                            forme s et de type d
        ones(s, d)          initialisation à 1 de        v = zeros([2, 2], bool)
                            forme s et de type d
        shape               attribut (sans pa-            u.shape
                            renthèse !) forme
        size                attribut taille               u.size
        dtype               attribut type des             u.dtype
                            données
        flatten()           méthode qui convertit        u.flatten()
                            en ligne (première puis
                            seconde...)
        reshape(s)          méthode qui change la        x.reshape([1, 3])
                            forme (la taille doit
                            être invariante)

      liste = 2*[1, 1] #liste = [1, 1, 1, 1]
      t = 2*np.array([1, 1]) #t =[2, 2]
      print(t.dtype)
      print(t**50) #2**50 serait negatif!

   • le slicing ne produit pas une copie des données comme pour les listes, mais une vue c’est
     à dire un extrait du tableau initial. Pour une copie, il faut utiliser la méthode .copy().
      liste = list(range(10))
      lliste = liste[:] #copie
      lliste[0] = 5 #liste n’est pas modifie
      print(liste)

      t = np.array(liste)
      u = t[:] #vue complete de t
      u[0] = 5 #t est modifie
      print(t)
      v = t.copy()
      v[0] = 0 #t n’est pas modifie
      print(t)

2.2.5     Sauvegarde
   La commande np.save enrgegistre (à l’adresse choisie) les données rassemblées dans un
tableau numpy. La taille du fichier est la taille des données (par exemple pour 1000 nombres
float64, 8000 octets) augmentée de 80 octets (pour la description du tableau, du type de
données).

                                                12
import numpy as np
    import numpy.random as rd
    import os

    dir(rd)
    help(rd.rand)

    t = rd.rand(1000)
    print(t.mean())
    np.save("H://cours3//hasard.npy", t)
    print(os.path.getsize("H://cours3//hasard.npy"))

    s = np.load("H://cours3//hasard.npy")
    print(s.mean())

2.3      matplotlib
   Consulter http://matplotlib.org/1.3.0/api/pyplot_summary.html pour une liste de
commandes.

2.3.1     Syntaxe minimale
                                                            
                                                                x(t) =    sin(t) 
   Représentation graphique de la courbe paramétrée                             .
                                                                y(t) = sin t + π4
    from math import pi
    import numpy as np
    import matplotlib.pyplot as plt

    t = np.linspace(0, 2*pi, 200)
    x = np.sin(t)
    y = np.sin(t + pi/4)
    plt.clf() #effacer le contenu de la fenetre graphique
    #ou plt.close() : fermer la fenetre
    plt.plot(x, y)
    plt.plot(x, -y)
    plt.show()

    Toutes les instructions graphiques sont représentées dans la même fenêtre (tant qu’elle
active, c’est à dire ni effacée ni fermée), sauf si on crée explicitement plusieurs figures actives
avec plt.figure(2) etc... On peut alors ”naviguer” d’une figure à l’autre :
    import matplotlib.pyplot as plt

    t = np.linspace(0, 2*np.pi, 100)
    plt.plot(t, np.sin(t))
    plt.figure(2)
    plt.plot(t, np.cos(t))
    plt.figure(1)
    plt.plot(t, abs(np.sin(t)))

2.3.2     Lignes de niveau
   Deux exemples :

                                                       13
import numpy as np
    import matplotlib.pyplot as plt

    #lignes de niveau de l’energie du pendule
    plt.close()
    x = np.linspace(-5, 5, 200)
    y = np.linspace(-1.5, 1.5, 100)
    xx, yy = np.meshgrid(x, y)
    z = yy**2/2-np.cos(xx)
    h = plt.contour(x,y,z,levels=np.linspace(-1, 2, 15),colors=’b’)
    plt.clabel(h, inline=1, fontsize=10)

    #lignes de niveau de (x**2+y**2)**2-2*x*y
    plt.close()
    x = np.linspace(-1, 1, 400)
    y = np.linspace(-1, 1, 400)
    xx, yy = np.meshgrid(x, y)
    z = (xx**2+yy**2)**2-2*xx*yy
    h = plt.contour(x,y,z,levels=np.linspace(-0.02, 0.11, 5))
    plt.clabel(h, inline=1, fontsize=10)
    plt.axhline()
    plt.axvline()
    plt.axis(’equal’)

   WARNING : les trois paragraphes suivants ne sont pas fondamentaux...

2.3.3     Syntaxe enrichie
   • Différents styles de trait (ls ou linestyle) ls=’’ (pas de trait), ’-’ (trait continu),
     ’--’ (pointillé)...

   • Différents styles de point marker=’+’ (croix), ’o’ (cercle)...

   • Couleurs des traits et symboles color=’k’ (noir), ’r’,’b’ (rouge, bleu)...

   • Repère orthonormé : plt.axes(aspect=’equal’)

   • Légende (à l’intérieur de plot, déclarer un label, et l’écrire dans la fenêtre active avec
     legend())

   Voir la documentation http://matplotlib.org/api/pyplot_summary.html et un exemple
en 2.4.3.

2.3.4     Images
    La commande plt.imshow() permet de visualiser des images au format .png ou des ma-
trices (RGB couleur, RGBA couleur avec transparence ou monochromes). emplies de flottants
entre 0. et 1.
Consulter pour plus de précisions
http://matplotlib.org/1.3.0/api/pyplot_api.html#matplotlib.pyplot.imshow
(et aussi l’exemple http://matplotlib.org/1.3.0/users/image_tutorial.html)

création et visualisation de matrice Sélection des points (x, y) dont l’image z = f (x, y) =
      (x2 + y 2 )2 − 2xy est proche de 0.

                                                      14
import numpy as np
      import matplotlib.pyplot as plt

      n = 1000
      epsilon = 0.01
      c = 0
      u, v = c+epsilon, c-epsilon
      x = np.linspace(-2, 2, n)
      y = np.linspace(2, -2, n)

      xx, yy = np.meshgrid(x, y, indexing=’xy’)
      z = (xx**2+yy**2)**2-2*xx*yy
      t = np.logical_or(z>u, z
2.4     scipy
2.4.1    Résoudre des équations
À une inconnue
   Les fonctions newton, bissect et brentq du module scipy.optimize permettent la résolution
approchée des équations à une seule inconnue.
   import scipy.optimize as optim
   import numpy as np
   import matplotlib.pyplot as plt

   def f(x):
       return(np.exp(x)-5*x)

   #exploration graphique
   x = np.linspace(-1, 5, 100)
   y = f(x)
   plt.plot(x, y)
   z = np.zeros(100, dtype = np.float)
   plt.plot(x, z)
   plt.show()

   #resolution par dichotomie
   print(optim.bisect(f, 0, 0.5))
   print(optim.bisect(f, 2, 3))

   #methode de Newton
   def fp(x):
       return(np.exp(x)-5)

   print(optim.newton(f, 0.2, fp))
   print(optim.newton(f, 2, fp))

   #resolution "rapide et sure" d’après scipy
   print(optim.brentq(f, 0, 0.5))
   print(optim.brentq(f, 2, 3))

À plusieurs inconnues
   Les fonctions root et fsolve du module scipy.optimize permettent la résolution ap-
prochée des équations à plusieurs inconnues.
   import scipy.optimize as optim

   def f(x):
       return([x[0]**2-2*x[0]*x[2]+5, x[0]*x[1]**2+x[1]*x[2]+1, 3*x[1]**2-8*x[0]*x[2]])

   print(optim.root(f, [0.5, -2.5, 3.5]))

   print(optim.fsolve(f, [0.5, -2.5, 3.5]))

2.4.2    Intégrer
                             Z     5
                                       exp(t)
   Calcul approché de                        dt.
                               1         t
   from math import exp
   import numpy as np
   from scipy.integrate import quad

   def f(x):
       return(exp(-x)/x)

   print(quad(f, 1, 5))#renvoie le couple (estimation, incertitude)

                                                     16
(Fichier quadrat.py)

2.4.3     Résoudre une ODE
Premier ordre
   Résolution de l’équation différentielle x0 (t) = x(t)2 − t avec les conditions initiales x(0) =
−1 puis x(0) = 0, x(0) = 0.1, x(0) = 0.2, pour représenter des solutions lorsque t ∈ [0, 10].
    import numpy as np
    from scipy.integrate import odeint
    import matplotlib.pyplot as plt

    def f(x,t):
        return(x*x-t)

    t = np.linspace(0, 10, 200)
    sol = odeint(f, -1, t)
    plt.grid()
    plt.plot(t, sol)
    plt.show()

    for k in range(3):
        sol = odeint(f, k/10, t)
        plt.plot(t, sol)
    plt.show()

   (Fichier odeOrdre1.py)

Second ordre
    Résolution de l’équation différentielle du pendule simple x00 t) = − sin(x(t)) avec diverses
conditions initiales (x(0) = 0, x0 (0) = 1 ou x(0) = 1, x0 (0) = 0 par exemple).
    Il faut l’écrire comme un système d’équations différentielles du premier ordre, en intro-
duisant unedeuxième fonction inconnue v(t) = x0 (t), la vitesse.
                 x0 (t) =     v(t)
Le système       0                  s’écrit aussi u0 (t) = f (u(t), t) en posant u(t) = [x(t), v(t)] et
                 v (t) = sin(x(t))
f (u, t) = (v(t), − sin(x(t)).

                                                   17
from math import sin
   import numpy as np
   from scipy.integrate import odeint
   import matplotlib.pyplot as plt

   #equation du pendule
   def f(xv, t):
       return([xv[1], -sin(xv[0])])
   #equation linearisee
   def g(xv, t):
       return([xv[1], -xv[0]])

   #graphes de solutions (t, x(t))
   t = np.linspace(0, 10, 200) #numpy
   sol = odeint(f, [1, 0], t) #scipy->numpy
   sol_lin = odeint(g, [1, 0], t)
   plt.close() #matplotlib...
   plt.grid()
   plt.plot(t, sol[:,0], color=’k’, label=’ equation non lineaire’)
   plt.plot(t, sol_lin[:,0], ls=’--’, color=’b’, label=’equation linearisee’)
   plt.ylim(-1.5,1.1)
   plt.legend(loc=’lower right’)
   plt.show()

   plt.clf()
   #courbes de phase (x(t), v(t))
   plt.plot(sol[:,0], sol[:,1], color=’k’, label=’ equation non lineaire’)
   plt.plot(sol_lin[:,0], sol_lin[:,1], ls=’--’, color=’b’, label=’equation linearisee’)
   xmin, xmax = plt.xlim()
   plt.xlim(xmin-0.1, xmax+0.1)
   ymin, ymax = plt.ylim()
   plt.ylim(ymin-0.5, ymax+0.1)
   plt.legend(loc=’lower right’)
   plt.show()

   sol est un tableau de 200 couples [x[i],v[i]].
sol[:,0] est le tableau des x[i] et sol[:,1] est celui des y[i]

                                                     18
Chapitre 3

Représentation binaire de données

3.1        Entiers en base 2
    Les nombres entiers sont habituellement écrits en base 10 : notant c1,c2,...,cn des
chiffres entre 0 et 9 et c0 un chiffre entre 1 et 9, la notation c0c1...cn désigne le nombre
Xn
    ck 10n−k . La notation commence par les chiffres de poids fort (c0,c1...) et finit par le
k=0
chiffre des unités cn.
    On peut écrire les nombres entiers dans toute base b (supérieure à 2) en utilisant des
                                                            Xd
chiffres qui seront compris cette fois entre 0 et b-1 : N =     ck bd−k .
                                                            k=0                  
                                                                            ln N
    La longueur d + 1 de la représentation de N en base b est 1 +                  (puisque N est
                                                                             ln b
                     X d
                d
compris entre b et       (b − 1)bk = bd+1 − 1).
                            k=0
    En raison du fonctionnement physique de l’ordinateur (qui s’appuie sur des circuits à 2 po-
sitions), la base b=2 est omniprésente en informatique. Chaque donnée stockée sur un circuit
est un bit (conventionnellement 0 ou 1), et un octet est un paquet de 8 bits consécutifs.
    La commande bin donne l’écriture binaire d’un nombre (qui est une chaı̂ne de caractères
commençant par le préfixe ’0b’). On peut aussi écrire une fonction qui donne la liste des
chiffres binaires. Il est commode de commencer par les unités, d’où si on veut respecter
la convention (big endian) 1 qui commence par les poids forts, l’application finale de la
méthode reverse().
      print(bin(353))

      def binaire(n):
          """Ecriture binaire, en écrivant à gauche les poids forts."""
          liste = []
          while n>0:
              liste.append(n%2)
              n = n//2
          liste.reverse()
          return liste

      print(binaire(353))
      print(hex(353))

  1. https://en.wikipedia.org/wiki/Endianness

                                                          19
Base hexadécimale
   Pour faciliter la lecture, la représentation binaire est souvent convertie en base 16 hexadécimale.
Les chiffres sont alors 0,1,2,3,4,5,6,7,8,9,a,b,c,d,e,f. La conversion est aisée : par
tranches de quatre chiffres binaires en commençant à droite depuis les unités, on évalue le
nombre qui sécrit ainsi en base 2. Par exemple la tranche 1011 (écriture décimale du nombre
11) sécrit avec le chiffre hexadécimal b. Le nombre 353 s’écrit en binaire 1 0110 0001 (on a
groupé les chiffres par 4) et en hexadécimal 161.
   La commande hex donne l’écriture hexadécimale d’un nombre (qui est préfixée par ’0x’).

Opérations binaires
   L’addition de deux nombres en écriture binaire nécessite seulement de gérer des retenues.
Par exemple l’addition de 353 et 68 :

      1 0 1 1 0 0 0 0 1
          1 0 0 0 1 0 0
     ------------------
      1 1 0 1 0 0 1 0 1

    En décalant vers la droite l’écriture binaire d’un nombre, on effectue la multiplication par
2. On réalise ainsi la multiplication par combinaison d’additions et de décalages. Par exemple
353 × 68 :

        1 0 1 1 0 0 0 0 1 0 0 (4 fois 353)
1 0 1 1 0 0 0 0 1 0 0 0 0 0 0 (64 fois 353)
-----------------------------
1 0 1 1 1 0 1 1 1 0 0 0 1 0 0

Type uint de numpy
    Le module numpy propose un type d’entier non signé (unsigned integer) encodé sur 4 oc-
tets (d’où la précision possible uint32 pour le distinguer d’autres types existants). Il faut être
conscient des conséquences d’un dépassement de capacité : si un décalage (ou une retenue)
fait dépasser la capacité d’encodage du résultat, les bits excédentaires sont tout simplement
effacés ! Seuls les nombres compris entre 0 et 232 −1 = 4294967295 sont correctement encodés.
    t = np.array([2, 3], np.uint)
    for k in range(5):
        t = t*t
        print(t)

    In [40]: (executing lines 46 to 49 of "cours_encodage.py")
    [4 9]
    [16 81]
    [ 256 6561]
    [     65536 43046721]
    [           0 3793632897] #faux

    In [41]: print(2**32, 3**32, 3**32%2**32)
    4294967296 1853020188851841 3793632897

3.2      Entiers relatifs
   Le module numpy propose (entre autres) un type d’entier relatif int32 qui est aussi abrégé
en int, qui permet d’encoder les entiers compris entre −231 et 231 − 1.

                                                      20
• un nombre positif ou nul n est encodé directement comme l’entier non signé n

   • un nombre négatif n est encodé comme l’entier non signé n + 232

Exemples :

   • 123 est encodé sur un octet par 01111011 (et sur 4 octets en commençant par 3 octets
     de zéros...)

     In [1]: bin(123)
     Out[1]: ’0b1111011’

   • -123 est encodé sur quatre octets comme 232 − 123 =4 294 967 173, ce qui donne
     11111111 11111111 11111111 10000101
     Le passage à l’opposé se traduit par

         – le complément à 2 (on remplace tous les 0 par 1 et réciproquement) :
            (123) 00000000 00000000 00000000 01111011
                  11111111 11111111 11111111 10000100
         – suivi de l’addition de 1 (ce qui peut entraı̂ner une succession de retenues)

Avec ces conventions, les dépassements de capacité sont encore plus surprenants que pour
les entiers non signés.
    s = np.array([2, 3], np.int)
    for k in range(5):
        s = s*s
        print(s)

    In [52]: (executing lines 54 to 57 of "cours_encodage.py")
    [4 9]
    [16 81]
    [ 256 6561]
    [   65536 43046721]
    [         0 -501334399]

    In [53]: 3**32
    Out[53]: 1853020188851841

    In [54]: 2**32+s[1] #entier uint encodant s[1]
3.3       Flottants
     https://docs.python.org/3/library/stdtypes.html?highlight=float#float.hex
     L’implémentation des nombres flottants suit la norme internationale IEEE754 de 1985. 2
     Le type float (par défaut) de PYTHON est encodé sur 8 octets (float64) : le premier bit
pour le signe, les 11 bits suivants pour l’exposant, les 52 bits restants pour la mantisse :
n = s2e m.
     A cause du bit de signe s, 0 est encodé deux fois.
     L’exposant e est un entier compris entre -1022 et 1023. Il est encodé sous la forme
uint(e+1023). On notera que les encodages par uint(0) et uint(2047) (211 − 1 = 2047)
sont libres : ils servent à encoder le zéro et l’infini.
                                                               52
                                                              X   dk
     La mantisse est un nombre compris entre 1 et 2. m = 1 +       k
                                                                     est encodé par les 52 bits
                                                              k=1
                                                                  2
dk .

Nombres représentables
   • Le plus grand nombre (notons le MAX) représentable est
                          52
                                !
                         X   1                 −53
               21023 1 +             1024
                                                   
                              k
                                  = 2     1 − 2      ≈ 1.7976931348623157e + 308
                         k=1
                             2

   • le plus petit nombre (notons le min) représentable est

                                             2−1022 ≈ 2.2250738585072014e − 308.

   • Zéro est encodé par un bit de signe ± suivi de 63 bits nuls.
      Un bit de signe ± suivi de 11 bits nuls puis de 52 bits non tous nuls n’est pas un nombre (ce serait l’encodage d’un nombre inférieur
      à min). On parle parfois de zéro non normalisé.

   • Les deux infinis sont encodés par un bit de signe, 11 bits égaux à 1 suivis de 52 bits
     nuls.
      Un bit de signe ± suivi de 11 bits égaux à 1 puis de 52 bits non tous nuls n’est pas un nombre (ce serait l’encodage d’un nombre
      supérieur à MAX). PYTHON les désigne par le nom Nan (Not a number).

Toutes ces informations sont accessibles dans le module sys.
    import sys

    print(sys.int_info)
    print(sys.float_info)

    In [59]: (executing lines 60 to 63 of "cours_encodage.py")
    sys.int_info(bits_per_digit=30, sizeof_digit=4)
    sys.float_info(max=1.7976931348623157e+308, max_exp=1024, max_10_exp=308,
    min=2.2250738585072014e-308, min_exp=-1021, min_10_exp=-307, dig=15, mant_dig=53,
     epsilon=2.220446049250313e-16, radix=2, rounds=1)

  2. https://en.wikipedia.org/wiki/IEEE_floating_point

                                                                  22
Arrondis
    La représentation d’un nombre est arrondie au plus proche. Par exemple, le nombre
décimal 0.1 n’est pas représenté exactement : son signe est +, son exposant est -4 et sa
mantisse est (en hexadécimal) 999999999a.
                                                                                   1
    En effet 1 ≤ 24 × 0.1 = 1.6 < 2, d’où l’exposant -4, et 1.6 = 1 + + 0.1, ce qui
                                                                               2
                                                    1              1
donne le développement illimité 0.1 = 2−4 1 + + 2−4 1 + + . . . . La mantisse répète
                                                    2              2
indéfiniment la succession de bits 1001 c’est à dire 9. Sa représentation la copie 13 fois et le
                           1
reste est plus grand que 53 d’où l’arrondi du treizième bloc à 1010 c’est à dire a.
                          2
      print(float.hex(0.1))

      In [62]: (executing line 75 of "cours_encodage.py")
      0x1.999999999999ap-4

     Cet arrondi a des conséquences dès qu’on effectue quelques additions comme ci-dessous :
      x = 0.1
      for k in range(9):
          x = x+0.1
          print(x)

      In [63]: (executing lines 70 to 73 of "cours_encodage.py")
      0.2
      0.30000000000000004
      0.4
      0.5
      0.6
      0.7
      0.7999999999999999

3.4          Caractères
https://docs.python.org/3/howto/unicode.html
http://pyvideo.org/video/289/pycon-2010--mastering-python-3-i-o

Caractères ASCII
   Un alphabet réduit à 128 caractères est encodé sur un octet : l’alphabet ASCII. Certains
de ses caractères ne sont pas imprimables (ils ne servent qu’à communiquer en langage ma-
chine). Les caractères accentués chers aux français ne sont pas disponibles.
     Théoriquement, un octet permet d’encoder 256 caractères différents. Cette possibilité est exploitée par l’alphabet Latin-1 (défini par
une norme internationale) ou l’alphabet propriétaire de Microsoft cp-1252. La limitation à 128 caractères ASCII provient de l’utilisation
du huitième bit comme bit de parité, à des fins de détection d’erreur : ainsi, la lettre a, qui porte le numéro 97 est encodée par les 7 bits
1100001 auquel on ajoutait le bit de parité 1. En cas de transmission erronée, si un seul bit est faux, l’erreur sera décelée. Voir le thème
Codage correcteur d’erreurs.

Unicode
   La mondialisation des échanges a rendu indispensable une normalisation de l’encodage de
tous les caractères utilisés à la surface de la terre. C’est le rôle de l’Unicode. Comme dans la
table ASCII, chaque caractère est repéré par un numéro. Les 128 premiers numéros sont ceux
de la table ASCII, et la numérotation est ouverte pour accueillir si nécessaire de nouveaux
caractères : actuellement plus de cent mille caractères...
   L’alphabet grec est repéré par la tranche 945-969, et le symbole de l’euro par 8364.

                                                                       23
Figure 3.1 – Les 128 caractères ASCII

    alpha = ""
    for k in range(945, 970, 1):
        alpha += chr(k)
    print(alpha)

    print(chr(8364))

Encodages
   L’encodage courant de la norme Unicode s’appelle utf-8.
Avec cette méthode, les caractères ASCII sont encodés sur un octet, les autres caractères
usuels sont encodés sur deux octets, et seuls des caractères exotiques nécessitent trois ou
quatre octets.

   • Sur un octet, le code ASCII est précédé du bit 0. Ainsi la lettre a est encodée par
     01100001.

   • Sur deux octets, le numéro est représenté par une séquence de 11 bits, ce qui permet
     de représenter les numéros de 128 à 2047. Les 5 bits de tête sont précédés du préfixe
     110 3 , et les six bits suivants sont précédés du préfixe 10 4 .
     La lettre accentuée é a pour numéro 233, qui sécrit (faire la succession de divisions
     euclidiennes par 2 en notant les restes : 233 = 2 × 116 + 1, 116 = 2 × 58 etc...) sur 11
     bits : 00011101001. L’encodage sur 2 octets est donc 110 00011 10 101001 5 .
  3. qui indique l’octet ouvrant un encodage sur deux octets
  4. qui indique que cet octet prolonge un encodage déjà ouvert
  5. les préfixes ont été détachés des autres bits.

                                                     24
• Vous irez lire la page suivante pour trois ou quatre octets :
     http://en.wikipedia.org/wiki/UTF-8 où il est expliqué pourquoi le symbole de l’euro
     est encodé sur trois octets : 1110 0010 10 000010 10 101100

   • Un octet qui commence par 0 encode un caractère ASCII.
     Un octet qui commence par 110 est suivi d’un octet qui commence par 10.
     Un octet qui commence par 1110 est suivi de deux octets qui commencent par 10.

    In [8]: ord(’é’)
    Out[8]: 233

    In [9]: bin(233)
    Out[9]: ’0b11101001’

    In [10]: hex(233)
    Out[10]: ’0xe9’

    In [11]: ’é’.encode(’latin-1’)
    Out[11]: b’\xe9’

    In [12]: ’é’.encode(’utf-8’)
    Out[12]: b’\xc3\xa9’

3.5      Conclusion
    La représentation binaire de nombreux autres objets resterait à étudier. Elle est souvent
compliquée par la multiplicité de formats concurrents (par exemple pour les images fixes :
pgm, png, jpeg entre autres...). Les alphabets qui ont précédé l’Unicode (et qui sévissent
encore...) illustrent les difficultés transitoires jusqu’à ce qu’une solution pérenne et univer-
sellement acceptée s’impose. Même la représentation des nombres (ne serait-ce que par la
problématique big or little endian) est compliquée.
    Les programmes se chargent de tout (encodage et décodage) et on n’a pas besoin de
connaı̂tre les détails de la représentation binaire. Cependant, particulièrement pour les fi-
chiers .txt, l’absence de précision de l’encodage (essentiellement Latin-1 ou utf-8) est la
source de nombreuses erreurs.

   Trois points à retenir :

       • tout objet est codé sous la forme d’une séquence de bits groupés par 8 en
         octets.

       • la méthode d’encodage doit être connue pour qu’on puisse interpréter le
         contenu d’une séquence de bits (c’est à dire la décoder). L’extension d’un fi-
         chier (par exemple .txt, .png, .jpeg) sert à désigner quel programme a été
         utilisé pour encoder et surtout quel programme appeler pour décoder.

       • un nombre flottant (standard) est codé sur 8 octets

                                                25
Chapitre 4

Fonctions

4.1      Généralités
4.1.1     En tête
   La définition d’une fonction (ou procédure) commence par le nom réservé def :
    def nom(arguments):

    suivi d’un bloc indenté qui contient les instructions.
    Il est utile de documenter 1 ses fonctions, pour faciliter leur prise en main par d’autres
utilisateurs (ou pour soi-même quand on la reprend après quelque temps). Consulter l’aide
sur une fonction de PYTHON (par exemple help(list.append)). Un commentaire encadré
entre deux occurrences de triple guillemets (""") peut s’étendre sur plusieurs lignes.

4.1.2     Valeur de retour
   L’instruction return variables met fin à l’exécution et retourne dans le cours de la ses-
sion la donnée qui suit return (des données multiples doivent être rassemblées dans un tuple,
une liste, une chaı̂ne de caractères ou un tableau).
    def div_euclid(a, b):
        """Calcule le quotient et le reste dans la division euclidienne de a par b, entiers naturels."""
        q, r = 0, a
        while r>=b: #invariant de boucle b*q+r égal à a
            q, r = q+1, r-b
        return (q, r)

    print(div_euclid(27, 5))

    La séquence d’instructions peut comporter plusieurs return (dans le cas d’instructions
conditionnelles), mais bien sûr lors d’une exécution, un seul est exécuté, mettant un terme
en retournant des valeurs.
    La séquence peut aussi ne pas comporter de return. Dans ce cas, il revient au même de
d’écrire juste avant la fin du bloc l’instruction return None. Les fonctions sans valeur de re-
tour explicite retournent en effet le nom réservé None. On les appelle parfois des procédures.
    Par exemple, la méthode append de la classe d’objets list est une procédure. Vous serez
donc déçu par le code suivant :
    L = [] #liste vide

    L = L.append(1)
    print(L)

    L.append(2)

  1. https://www.python.org/dev/peps/pep-0257/

                                                      26
en revanche, celui-ci fonctionne très bien :
     L = []

     for k in range(5):
         L.append(k)

     print(L)

    même si PYTHON offre des syntaxes plus brèves comme :
     L = list(range(5))

     L = [k for k in range(5)]

    On doit de même distinguer clairement return (qui met un terme à la fonction en four-
nissant une valeur de retour) et print qui est une commande ordinaire qui produit un effet
(affichage sur le périhpérique écran).

4.2         Portée des variables
4.2.1         Nom de variable
   Toute succession de lettres et de chiffres ou de symboles (notamment l’underscore _)
qui commence par une lettre est une nom valable et peut servir de référence à une adresse
mémoire après affectation. Ainsi 007JB = ’Daniel Craig’ déclenche un message d’erreur,
alors que ce qui suit est correct :

JB007 = ’Daniel Craig’
print(id(JB007)) #adresse mémoire

    Certains noms sont cependant réservés au langage Python. En voici la liste :

Logique : True, False, None, and, or, not, is

Construction : class, def, lambda,global, nonlocal

Contrôle : if, elif, else, while, for, in, return, assert,
    break, continue, pass, try, except, finally, raise, yield

Gestion de modules, de fichiers, de noms : from, import, as, with, del

    Il est conseillé de choisir des noms explicites, qui facilitent la compréhension du pro-
gramme. Par exemple longueur plutôt que l etc...
    Dans cette optique, les raccourcis suivants sont appréciables si le nom de la variable
est plus long que x (mais ils nuisent à la lisibilité et peuvent avoir des effets difficilement
prévisibles : voir 4.3.3

x   = 0
x   += 1      #remplace x = x + 1
x   *= 2      #x = x * 2
x   **= 3     #x = x**3
x   %= 3      #x = x%3, reste modulo 3
x   //= 3     #x = x//3, division euclidienne

                                                27
4.2.2       Variables globales
   Les affectations dans la session définissent des variables globales qui jouent le rôle de
constantes.
    a = 3

   Ces variables sont associés à leur valeur dans toute instruction
    print(a+5)

    et dans toute fonction où une variable locale qui porte le même nom ne lui fait pas
écran (voir le paragraphe suivant)
    def f(x):
        return a*x

    print(a, f(1))

4.2.3       Liaison dynamique
    Simple et IMPORTANT :
Si une variable globale intervient dans le corps d’une fonction, la valeur qui sera prise
en compte lors d’une exécution est la valeur au moment de l’exécution, qui n’est pas
nécessairement la même qu’au moment de la définition de cette fonction. On parle de liai-
son dynamique (tous les langages ne fonctionnent pas ainsi).
    a = 3

    def f(x):
        """Multiplie x par la valeur courante de a."""
        return a*x

    print(f(1)) #3

    a = 5 #la modification sera prise en compte pour toute execution ulterieure

    print(f(1)) #5

4.2.4       Variables locales
   Toute variable affectée dans le corps d’une fonction est locale : on ne peut l’utiliser dans la
session principale, et une variable du même nom dans la session principale (ou dans d’autres
fonctions) est totalement indépendante de cette variable locale.
    def f(x):
        """Multiplie x par 3."""
        b = 3
        return b*x

    print(f(1)) #3
    print(b) #erreur, sauf si une variable globale b a ete definie anterieurement

  Une variable locale fait écran au sein de la fonction à toute variable globale de même
nom.
    a = 3

    def g(x):
        """Multiplie x par 2."""
        a = 2 #variable locale
        return a*x

    print(a, g(1)) #3, 2

                                                         28
Il est déconseillé de changer ce comportement en déclarant explicitement des variables
globales (avec le nom réservé global) dans les fonctions.
    a = 3

    def f(x):
        """Affecte 2 a la variable a et multiplie x par 2."""
        global a
        a = 2
        return a*x

    print(a, f(1)) #2, 2

4.2.5       Fonctions locales
    Pour définir une fonction complexe, il est plus sûr de fractionner le code en un certain
nombre de fonctions élémentaires. Ces fonctions peuvent être globales, mais aussi locales à
la fonction appelante. L’avantage de fonctions locales réside dans le passage automatique des
paramètres de la fonction appelante à ces fonctions locales. Nous illustrons cela sur l’exemple
de la recherche d’une chaı̂ne au sein d’un texte.

Algorithme Etant donné deux chaı̂nes de caractères mot et texte, on examine pour chaque
    caractère de texte si une occurence de mot commence à ce caractère.

Avec slicing La technique du slicing permet de créer une sous-chaı̂ne de caractères (de-
    puis l’indice de début jusqu’à l’indice de fin exclu).
      def recherche(mot, texte):
          """Decide si la chaine de caracteres ’mot’ est une sous-chaine de la chaine ’texte’."""
          p, q = len(mot), len(texte)
          for i in range(q-p+1):
              if mot == texte[i:i+p]: #slicing
                  return True
          return False

      #des tests
      u=’cours’
      v="le concours de l’ecole polytechnique"
      print(recherche(u, v))

      u=’tecnique’
      print(recherche(u, v))

      u=’technique’
      print(recherche(u, v))

Fonction globale On peut remplacer le test d’égalité par une fonction globale d’égalité entre
    deux chaı̂nes. La fonction de recherche utilise encore le slicing (donc crée une chaı̂ne
    annexe).
    Pour varier un peu, la fonction recherche_bis retournera, si elle le trouve, le premier
    indice dans le texte où commence une occurence du mot.

                                                      29
def egal(mot1, mot2):
          """Teste si deux chaines de caracteres sont egales."""
          p, q = len(mot1), len(mot2)
          if p != q:
              return False
          else:
              for i in range(p):
                  if mot1[i] != mot2[i]:
                      return False
              return True

      def recherche_bis(texte, mot):
          """Renvoie l’indice de debut de la premiere
          occurence de ’mot’ dans ’texte’ et None sinon."""
          p, q = len(texte), len(mot)

          for debut in range(p-q+1):
              mot2 = texte[debut:debut+q)
              if egal(mot, mot2):
                  return debut
          return None

Fonction locale Idem avec une fonction locale. Le code de la fonction egal est allégé, et il
    n’y a plus besoin de chaı̂ne annexe (produite par slicing).
      def recherche_ter(texte, motif):
          """Renvoie l’indice de debut de la première
          occurence de motif dans texte et None sinon."""
          p, q = len(texte), len(motif)

          def egal(debut): #fonction locale: texte, motif,
          p, q sont connus dans la procedure appelante
          donc de la procedure ’egal’ (a moins
          qu’une variable locale a ’egal’ porte le meme nom
          et fasse ecran...)
              for k in range(q):
                  if motif[k] != texte[debut+k]:
                      return False
              return True

          for i in range(p-q+1):
              if egal(i):
                  return i
          return None

Exercice Modifier le code pour qu’il n’y ait plus qu’un return par fonction et que les boucles
    (dont le nombre d’itérations dépend de l’instance traitée) soient contrôlées par while
    au lieu de for. Pour cela, vous aurez besoin d’un booléen qui répond à la question :
    ”Faut-il continuer ?”.

4.3      Passage des arguments
4.3.1     Passage par valeurs
   Les valeurs des arguments d’une fonction sont copiées lors d’une exécution. Les argu-
ments formels peuvent être utilisés comme des variables locales (c’est à dire affectées dans le
corps de la fonction). Ci-dessous des exemples caricaturaux où on s’acharne à noter avec le
même nom de nombreux objets différents.

                                                     30
a = 5

    def carre(a):
        """Elève le nombre a au carré."""
        a = a*a
        return(a) #les deux lignes peuvent etre résumées par return a*a

    print(a, carre(a))

    a = list(range(5))

    def repete(a):
        """Concatène la liste a avec elle m^
                                            eme."""
        a = 2*a
        return a #idem return 2*a résume les deux lignes

    print(a, repete(a))

    import numpy as np

    a = np.ones(5, int)

    def double(a):
        """Multiplie tous les éléments d’un tableau par 2."""
        a = 2*a
        return a #idem...

    print(a, double(a))

4.3.2       Fonction qui modifie ses arguments
    On vient d’expliquer que les arguments passés à une fonction ne sont pas modifiés (sauf
accident, voir le paragraphe suivant).
Ce comportement est ce qu’on souhaite en général : la fonction crée de nouveaux objets, de
nouvelles données sans modifier ce qui existait antérieurement dans la mémoire (globale).
Cependant, notamment pour le tri de données (qui peuvent remplir des tableaux très volu-
mineux), on peut souhaiter des méthodes qui trient sur place, c’est à dire qui rangent les
données dans le tableau initial sans créer une nouvelle structure de données aussi volumi-
neuse. L’espace mémoire du tableau fourni en argument est modifié par la fonction de tri
jusqu’à donner en sortie le tableau trié.
C’est possible pour les structures mutables que sont les listes et les tableaux, en manipulant
les éléments auxquels on accède par la notation indicée. 2
    Exemple du tri-bulle : pour ranger dans l’ordre croissant un tableau t de nombres de taille
n

Principe on effectue des parcours successifs de t au cours desquels on compare deux données
     d’indices consécutifs en les remettant dans l’ordre si nécessaire. Après un parcours com-
     plet, on est seulement assuré que le plus grand nombre est en dernière position, on n’a
     plus qu’à parcourir n-1 données, et ainsi de suite.

Algorithme Entrées : t est un tableau de taille n
      - pour p (le nombre de données restant à ranger) variant entre n et 2
            - pour i variant de 1 à p-1, comparer t[i-1] et t[i] et les ranger dans l’ordre
      croissant

Simulation Avec 5 données aléatoires :

      p=5, i=1, t=[7, 8, 5, 9, 1]
  2. Visualisation de l’exécution sur le site : http://pythontutor.com/

                                                        31
p=5,   i=2,      t=[7,   5,   8,   9,   1]
      p=5,   i=4,      t=[7,   5,   8,   1,   9]
      p=4,   i=1,      t=[5,   7,   8,   1,   9]
      p=4,   i=3,      t=[5,   7,   1,   8,   9]
      p=3,   i=2,      t=[5,   1,   7,   8,   9]
      p=2,   i=1,      t=[1,   5,   7,   8,   9]

Code itératif
             def tri_bulle(t):
                 n = len(t)
                 for p in range(n, 1, -1):
                     for i in range(1, p):
                         if t[i-1]>t[i]:
                             t[i-1], t[i] = t[i], t[i-1]
                 return None

4.3.3     Attention aux raccourcis
     WARNING : Inutile de lire ce paragraphe si vous n’employez jamais les raccourcis du
genre x += 1.
     On l’a vu dans le paragraphe 4.3.1 : les références passées en argument d’une fonction ne
sont pas modifiées par l’exécution de cette fonction (même si l’objet référencé est mutable,
comme les listes ou les tableaux.
Ce n’est plus vrai avec les raccourcis +=,*=,**= etc...Si on veut utiliser les raccourcis
avec des objets mutables, il faut commencer par faire explicitement une copie !
Dans les exemple ci-dessous, on a évité toute ressemblance entre paramètre formel (x)et
référence globlale (a), pour souligner que les différences viennent uniquement des raccourcis.
    a = list(range(5))

    def ddouble(x):
       x *= 2
       return x

    print(a, ddouble(a)) #a est modifie!!!

    a = list(range(5))

    def dddouble(x):
        y = x
        y *= 2
        return y

    print(a, dddouble(a)) #la aussi!!!

   Rappelons que listes et tableaux numpy ne se copient pas de la même façon. Pour être
certain de ne pas employer de fonction avec des objets auxquels elle n’est pas destinée, il suffit
de concevoir des méthodes (voir 4.4). On parlera peut-être plus tard de programmation
orientée objet...

                                                      32
a = list(range(5))

    def Double(a):
        a = a[:] #ou a=a.copy()
        a *= 2
        return a

    print(a, Double(a))

    a = np.ones(5, int)

    def DDouble(a):
        a = a.copy() #a[:] est une vue pour un tableau
        a *= 2
        return a #return(2*a) remplace les trois lignes

    print(a, DDouble(a))

4.3.4      Valeurs par défaut
   Les apprentis-sorciers fourbiront leurs armes en lisant https://docs.python.org/3/tutorial/
controlflow.html#more-on-defining-functions
    def genere_chaine(debut=65, fin=91):
        """Génère la cha^
                          ıne des caractères de numéro compris entre debut (inclus, valant 63 par défaut)
        et fin (exclu, valant 90 par défaut)."""
        c = ’’ #cha^ ıne vide
        for i in range(debut, fin):
            c = c + chr(i)
        return c

    print(genere_chaine())
    print(genere_chaine(fin=120))

4.4      Méthodes pour objets
    PYTHON est un langage orienté objet : pour chaque classe d’objets sont définies des fonc-
tions qu’on appelle dans ce cas des méthodes et des données annexes qu’on appelle des at-
tributs. La syntaxe utilise le point. Vous l’avez déjà employée avec les listes : liste.append(element)
    Autre exemple : les tableaux de numpy sont des objets dotés de l’attribut shape et des
méthodes flatten (sans argument, qui donne une copie) et reshape (qui donne une vue,
pas un tableau indépendant).
    import numpy as np

    m = np.ones([6, 8], int)
    print(m.shape) #attribut
    p = m.flatten() #methode
    q = m.reshape([12, 4])
    q[0] = 0 #modifie la premiere ligne de q
    print(m) #m a ete modifie
    print(p) #pas p qui est une copie

                                                         33
Chapitre 5

La structure de Pile

5.1     Structures de données
  Une certain nombre de structures de données sont disponibles en PYTHON (ou dans le
module numpy pour la dernière) :

   • les listes

   • les tuples

   • les chaı̂nes de caractères

   • les dictionnaires (que nous n’utiliserons pas)

   • les tableaux

Chacune de ces structures est riche de nombreuses fonctionnalités. Selon le problème traité,
l’une d’entre elles sera choisie parce qu’elle est plus commode ou plus efficace que les autres.
Le tableau ci-dessous présente uniquement les commandes sur les listes qui vont nous être
utiles pour une implémentation des piles. Il peut être complété par la consultation de https:
//docs.python.org/3/tutorial/datastructures.html#more-on-lists

                                   Table 5.1 – Méthodes de listes

    Méthode/fonction    Action                                             Syntaxe
    len                  retourne la longueur                               len(liste)
    append               ajoute un élément à la fin de la liste          liste.append(x)
    pop                  supprime et retourne l’élément en fin de liste   liste.pop()

5.2     La structure de pile
    La structure de pile n’est pas implémentée en PYTHON .
C’est une structure très primitive qui, dans sa version minimaliste, ne supporte que trois ac-
tions : la création, l’empilement et le dépilement.

Créer une pile initialement vide.

                                                 34
Vous pouvez aussi lire