Python : Pour aller plus loin

19 juillet 2014 rdorigny 0 commentaires

Dans l'article précédent, je vous ai montré les bases du langage de script Python. Voyons un peu plus profondément les différentes notions et fonctionnalités que propose Python.





Ce chapitre est un fork de la documentation fournie par Gérard Swinnen sur le site développez.com . Elle est très complète et détaillée, aussi j'ai jugé intéressant de la résumer pour ceux qui comme moi, se rebute à la lecture d'une documentation de plus de 300 pages. Ceci dit, si vous souhaitez aller plus loin, n'hésiter à la récupérer au format pdf.


1)Les chaines de caractères

1.1)Tableau de caractères

Les chaines de caractères se comportent comme des tableaux de caractères:
>>> ch = "Juliette" >>> print(ch[0:3]) Ju >>> print(ch[:3]) # les 3 premiers caractères Jul >>> print(ch[3:]) # tout ce qui suit les 3 premiers caractères iette

1.2)Concaténation et répétition

Python permet aussi la concaténation ou la répétition:
>>> n = 'abc' + 'def' # concaténation >>> m = 'zut ! ' * 4 # répétition >>> print(n, m) abcdef zut ! zut ! zut ! zut !

1.3)Appartenance

Autre mécanisme, l'instruction in qui vérifie si une séquence est présente dans une chaîne:
car = "e" voyelles = "aeiouyAEIOUYàâéèêëùîï" if car in voyelles: print(car, "est une voyelle")

De même dans un tableau:
n = 5 premiers = [1, 2, 3, 5, 7, 11, 13, 17] if n in premiers: print(n, "fait partie de notre liste de nombres premiers")

1.4)Les chaînes sont des séquences non modifiables

Vous ne pouvez pas modifier le contenu d ' une chaîne existante. En d ' autres termes, vous ne pouvez pas utiliser l 'opérateur [ ] dans la partie gauche d ' une instruction d ' affectation. Essayez par exemple d ' exécuter le petit script suivant (qui cherche intuitivement à remplacer une lettre dans une chaîne) :
salut = 'bonjour à tous' salut[0] = 'B' print(salut)

Le résultat attendu par le programmeur qui a écrit ces instructions est « Bonjour à tous » (avec un B majuscule). Mais contrairement à ses attentes, ce script lève une erreur du genre : TypeError: 'str' object does not support item assignment. Cett e erreur est provoquée à la deuxième ligne du script. On y essaie de remplacer une lettre par une autre dans la chaîne, mais cela n'est pas permis. Par contre, le script ci-dessous fonctionne parfaitement :
salut = 'bonjour à tous' salut = 'B' + salut[1:] print salut

Dans cet autre exemple, en effet, nous ne modifions pas la chaîne salut. Nous en re-créons une nouvelle, avec le même nom, à la deuxième ligne du script (à partir d'un morceau de la précédente, soit, mais qu'importe : il s'agit bien d'une nouvelle chaîne). A noter que les scripts Python que vous écrivez sont eux-mêmes des textes, bien entendu. Suivant la configuration de votre logiciel éditeur, ou de votre OS, ces textes pourront donc se retrouver encodés suivant différentes normes. Afin que Python puisse les interpréter correctement, il vous est conseillé d'y inclure toujours l'un des pseudo-commentaires suivants (obligatoirement à la 1e ou à la 2e ligne) :
# -*- coding:Latin-1 -*-
Ou bien :
# -*- coding:Utf-8 -*-
… en indiquant l'encodage effectivement utilisé, bien évidemment ! Ainsi l'interpréteur Python sait décoder correctement les chaînes de caractères littérales que vous avez utilisées dans le script. Notez que vous pouvez omettre ce pseudo-commentaire si vous êtes certain que vos scripts sont encodés en Utf-8, car c'est cet encodage qui est désormais la norme par défaut pour les scripts Python.

1.5)Les fonctions prédéfinies principales

Sans que la liste soit exhaustive, il y a:
  • split() : convertit une chaîne en une liste de sous-chaînes. On peut choisir le caractère séparateur en le fournissant comme argument, sinon c'est un espace par défaut,
  • join(liste) : rassemble une liste de chaînes en une seule (cette méthode effectue donc l'action inverse de la précédente). Attention : la chaîne à laquelle on applique cette méthode est celle qui servira de séparateur (un ou plusieurs caractères) ; l'argument transmis est la liste des chaînes à rassembler,
  • find(sch) : cherche la position d'une sous-chaîne sch dans la chaîne,
  • count(sch) : compte le nombre de sous-chaînes sch dans la chaîne,
  • lower() : convertit une chaîne en minuscules,
  • upper() : convertit une chaîne en majuscules,
  • title() : convertit en majuscule l'initiale de chaque mot,
  • swapcase() : convertit toutes les majuscules en minuscules, et vice-versa,
  • strip() : enlève les espaces éventuels au début et à la fin de la chaîne,
  • replace(c1, c2) : remplace tous les caractères c1 par des caractères c2 dans la chaîne,
  • index(car) : retrouve l'indice (index) de la première occurrence du caractère car dans la chaîne,
  • len(ch) renvoie la longueur de la chaîne ch, ou en d'autres termes, son nombre de caractères,
  • float(ch)convertit la chaîne ch en un nombre réel (float) (bien entendu, cela ne pourra fonctionner que si la chaîne représente bien un nombre, réel ou entier),
  • int(ch) convertit la chaîne ch en un nombre entier (avec des restrictions similaires),
  • str(obj) convertit (ou représente) l'objet obj en une chaîne de caractères. obj peut être une donnée d'à peu près n'importe quel type.
  • 1.6)Formatage des chaines

    Les balises à utiliser sont constituées d'accolades, contenant ou non des indications de formatage. La méthode format() doit recevoir autant d'arguments qu'il y aura de balises dans la chaîne. Si les balises sont vides, comme dans notre exemple, Python appliquera tout simplement la fonction str() aux arguments correspondants pour pouvoir les insérer à leur place dans la chaîne. Voici un exemple:
    >>> coul ="verte" >>> temp =1.347 + 15.9 >>> ch ="La couleur est {} et la température vaut {} °C" >>> print(ch.format(coul, temp)) La couleur est verte et la température vaut 17.247 °C

    ou
    >>> pi =3.1416 >>> r =4.7 >>> ch ="L'aire d'un disque de rayon {} est égale à {}." >>> print(ch.format(r, pi * r**2))

    L'aire d'un disque de rayon 4.7 est égale à 69.397944. Voilà pour le principe de base. La technique devient cependant bien plus intéressante encore si vous insérez des indications de formatage dans les balises. Par exemple, vous pouvez améliorer la présentation de la chaîne, dans l'exemple précédent, en limitant la précision du résultat final, en utilisant la notation scientifique, en fixant le nombre total de caractères, etc. Si vous insérez les indications suivantes dans la dernière balise, par exemple, vous obtiendrez respectivement :
    avec {:8.2f} : L'aire d'un disque de rayon 4.7 est égale à 69.40.
    avec {:6.2e} : L'aire d'un disque de rayon 4.7 est égale à 6.94e+01.

    Dans le premier essai, le résultat est formaté de manière à comporter un total de 8 caractères, dont 2 chiffres après le point décimal. Dans le second, le résultat est présenté en notation scientifique (e+01 signifie : « x 1001 »). Veuillez constater au passage que les arrondis éventuels sont effectués correctement. La description complète de toutes les possibilités de formatage comporterait plusieurs pages, et cela sort largement du cadre de ces notes. S'il vous faut un formatage très particulier, veuillez consulter la documentation en ligne de Python, ou des manuels plus spécialisés. Signalons simplement encore, que le formatage permet d'afficher très facilement divers résultats numériques en notation binaire, octale ou hexadécimale :

    >>> n = 789 >>> txt ="Le nombre {:d} (décimal) vaut {:x} en hexadécimal et {:b} en binaire" >>> print(txt.format(n,n,n)) Le nombre 789 (décimal) vaut 315 en hexadécimal et 1100010101 en binaire

    Python offre la possibilité d'utiliser un formatage comme on le connait en C:
    >>> coul ="verte" >>> temp = 1.347 + 15.9 >>> print("La couleur est %s et la température vaut %s °C" % (coul, temp)) La couleur est verte et la température vaut 17.247 °C

    La balise %s joue le même rôle que {} dans la nouvelle technique. Elle accepte n'importe quel objet (chaîne, entier, float, liste...). Vous utiliser aussi d'autres balises plus élaborées, telles que %8.2f, ou %6.2e, qui correspondent aux {:8.2f} et {:6.2e} de la nouvelle technique. C'est donc équivalent pour les cas les plus simples, mais soyez persuadés que les possibilités de la nouvelle formulation sont beaucoup plus étendues.

    2)Fonctionnalités autour des listes

    Dans le chapitre précédent, nous avions introduit la notions de liste (ou collection), voyons les fonctionnalités que Python nous propose dans le traitement d'une liste.

    2.1)Rappels

    Voyons par l'exemple:
    >>> nombres = [5, 38, 10, 25] >>> mots = ["jambon", "fromage", "confiture", "chocolat"] >>> stuff = [5000, "Brigitte", 3.1416, ["Albert", "René", 1947]]

    Pour accéder à liste:
    >>> print(nombres[2]) 10 >>> print(nombres[1:3]) [38, 10] >>> print(nombres[2:3]) [10] >>> print(nombres[2:]) [10, 25] >>> print(nombres[:2]) [5, 38] >>> print(nombres[-1]) 25 >>> print(nombres[-2]) 10

    Contrairement aux chaînes de caractères, les listes sont des séquences modifiables. Cela nous permettra de construire plus tard des listes de grande taille, morceau par morceau, d'une manière dynamique (c'est-à-dire à l'aide d'un algorithme quelconque). Exemples :
    >>> nombres[0] = 17 >>> nombres [17, 38, 10, 25]

    Dans l'exemple ci-dessus, on a remplacé le premier élément de la liste nombres, en utilisant l'opérateur [ ] (opérateur d'indiçage) à la gauche du signe égale. Pour parcourir une liste, il y a la boucle for
    >>> divers = [3, 17.25, [5, 'Jean'], 'coucou'] >>> for item in divers: ... print(item, type(item)) ... 3 <class 'int'> 17.25 <class 'float'> [5, 'Jean'] <class 'list'> coucou <class 'str'>

    2.2)Fonctions associées

    Les principales fonctions sont:
    >>> nombres = [17, 38, 10, 25, 72] >>> nombres.sort() # trier la liste >>> nombres [10, 17, 25, 38, 72] >>> nombres.append(12) # ajouter un élément à la fin >>> nombres [10, 17, 25, 38, 72, 12] >>> nombres.reverse() # inverser l'ordre des éléments >>> nombres [12, 72, 38, 25, 17, 10] >>> nombres.index(17) # retrouver l'index d'un élément 4 >>> nombres.remove(38) # enlever (effacer) un élément >>> nombres [12, 72, 25, 17, 10] >>> del nombres[2] >>> nombres [12, 72, 17, 10] >>> del nombres[1:3] >>> nombres [12, 10]

    2.3)Techniques du slicing

    C'est une technique qui permet de modifier une liste sans utiliser les méthodes append() et del.

    Pour ajouter des éléments:
    >>> mots = ['jambon', 'fromage', 'confiture', 'chocolat'] >>> mots[2:2] =["miel"] >>> mots ['jambon', 'fromage', 'miel', 'confiture', 'chocolat'] >>> mots[5:5] =['saucisson', 'ketchup'] >>> mots ['jambon', 'fromage', 'miel', 'confiture', 'chocolat', 'saucisson', 'ketchup']

    Pour supprimer ou modifier des éléments:
    >>> mots[2:5] = [] # [] désigne une liste vide >>> mots ['jambon','fromage','saucisson', 'ketchup'] >>> mots[1:3] = ['salade'] >>> mots ['jambon', 'salade', 'ketchup'] >>> mots[1:] = ['mayonnaise', 'poulet', 'tomate'] >>> mots ['jambon', 'mayonnaise', 'poulet', 'tomate']

    2.4)Opérations sur les listes

    >>> fruits = ['orange','citron'] >>> legumes = ['poireau','oignon','tomate'] >>> fruits + legumes ['orange', 'citron', 'poireau', 'oignon', 'tomate'] >>> fruits * 3 ['orange', 'citron', 'orange', 'citron', 'orange', 'citron'] >>> sept_zeros = [0]*7 >>> sept_zeros [0, 0, 0, 0, 0, 0, 0]

    2.5)copie de liste

    La commande list2=list1 ne réalise pas une copie réelle, mais créé juste une nouvelle référence vers la même liste.

    >>> fable = ['Je','plie','mais','ne','romps','point'] >>> phrase = fable >>> fable[4] ='casse' >>> phrase ['Je', 'plie', 'mais', 'ne', 'casse', 'point']

    3)Les nombres aléatoires

    Dans son module random, Python propose toute une série de fonctions permettant de générer des nombres aléatoires qui suivent différentes distributions mathématiques.
    >>> from random import *

    La fonction ci-dessous permet de créer une liste de nombres réels aléatoires, de valeur comprise entre zéro et un. L'argument à fournir est la taille de la liste :
    >>> def list_aleat(n): ... s = [0]*n ... for i in range(n): ... s[i] =random() ... return s ... >>> list_aleat(3) [0.37584811062278767, 0.03459750519478866, 0.714564337038124] >>> list_aleat(3) [0.8151025790264931, 0.3772866844634689, 0.8207328556071652]

    4)Les tuples

    Python propose un type de données appelé tuple , qui est assez semblable à une liste mais qui, comme les chaînes, n'est pas modifiable (à la différence des listes qui sont modifiables). Du point de vue de la syntaxe, un tuple est une collection d'éléments séparés par des virgules :
    >>> tup = 'a', 'b', 'c', 'd', 'e' >>> print(tup) ('a', 'b', 'c', 'd', 'e')

    Bien que cela ne soit pas nécessaire, il est vivement conseillé de mettre le tuple en évidence en l'enfermant dans une paire de parenthèses, comme la fonction print() de Python le fait elle-même. Il s'agit simplement d'améliorer la lisibilité du code.
    >>> tup = ('a', 'b', 'c', 'd', 'e')

    Les opérations que l'on peut effectuer sur des tuples sont syntaxiquement similaires à celles que l'on effectue sur les listes, si ce n'est que les tuples ne sont pas modifiables :
    >>> print(tup[2:4]) ('c', 'd') >>> tup[1:3] = ('x', 'y') ==> ***** erreur ! ***** Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: 'tuple' object does not support item assignment >>> tup = ('André',) + tup[1:] >>> print(tup) ('André', 'b', 'c', 'd', 'e')

    5)Les dictionnaires

    Les dictionnaires que nous découvrons ici constituent un autre type composite. Ils ressemblent aux listes dans une certaine mesure (ils sont modifiables comme elles), mais ce ne sont pas des séquences. Les éléments que nous allons y enregistrer ne seront pas disposés dans un ordre immuable. En revanche, nous pourrons accéder à n'importe lequel d'entre eux à l'aide d'un index spécifique que l'on appellera une clé, laquelle pourra être alphabétique, numérique, ou même d'un type composite sous certaines conditions. Comme dans une liste, les éléments mémorisés dans un dictionnaire peuvent être de n'importe quel type. Ce peuvent être des valeurs numériques, des chaînes, des listes, des tuples, des dictionnaires,...

    5.1)Création d'un dictionnaire

    Puisque le type dictionnaire est un type modifiable, nous pouvons commencer par créer un dictionnaire vide, puis le remplir petit à petit. Du point de vue de la syntaxe, on reconnaît un dictionnaire au fait que ses éléments sont enfermés dans une paire d'accolades. Un dictionnaire vide sera donc noté { } :
    >>> dico = {} >>> dico['computer'] = 'ordinateur' >>> dico['mouse'] ='souris' >>> dico['keyboard'] ='clavier' >>> print(dico) {'computer': 'ordinateur', 'keyboard': 'clavier', 'mouse': 'souris'}

    Comme vous pouvez l'observer dans la dernière ligne ci-dessus, un dictionnaire apparaît dans la syntaxe Python sous la forme d'une série d'éléments séparés par des virgules, le tout étant enfermé entre deux accolades. Chacun de ces éléments est lui-même constitué d'une paire d'objets : un index et une valeur, séparés par un double point. Dans un dictionnaire, les index s'appellent des clés, et les éléments peuvent donc s'appeler des pairesclé-valeur. Dans notre dictionnaire d'exemple, les clés et les valeurs sont des chaînes de caractères. Veuillez à présent constater que l'ordre dans lequel les éléments apparaissent à la dernière ligne ne correspond pas à celui dans lequel nous les avons fournis. Cela n'a strictement aucune importance : nous n'essaierons jamais d'extraire une valeur d'un dictionnaire à l'aide d'un index numérique. Au lieu de cela, nous utiliserons les clés :
    >>> print(dico['mouse']) souris

    Remarquez aussi que contrairement à ce qui se passe avec les listes, il n'est pas nécessaire de faire appel à une méthode particulière (telle que append()) pour ajouter de nouveaux éléments à un dictionnaire : il suffit de créer une nouvelle paire clé-valeur.

    5.2)Opération sur un dictionnaire

    Les opérations par l'exemple:
    >>> invent = {'pommes': 430, 'bananes': 312, 'oranges' : 274, 'poires' : 137} >>> print(invent) {'oranges': 274, 'pommes': 430, 'bananes': 312, 'poires': 137} >>> del invent['pommes'] >>> print(invent) {'oranges': 274, 'bananes': 312, 'poires': 137} >>> print(len(invent)) 3 >>> if "pommes" in invent: ... print("Nous avons des pommes") ... else: ... print("Pas de pommes. Sorry") ... Pas de pommes. Sorry

    5.3)Les méthodes prédéfinies

    La méthode keys() renvoie la séquence des clés utilisées dans le dictionnaire. Cette séquence peut être utilisée telle quelle dans les expressions, ou convertie en liste ou en tuple si nécessaire, avec les fonctions intégrées correspondantes list() et tuple() :
    >>> print(dico.keys()) dict_keys(['computer', 'mouse', 'keyboard']) >>> for k in dico.keys(): ... print("clé :", k, " --- valeur :", dico[k]) ... clé : computer --- valeur : ordinateur clé : mouse --- valeur : souris clé : keyboard --- valeur : clavier >>> list(dico.keys()) ['computer', 'mouse', 'keyboard'] >>> tuple(dico.keys()) ('computer', 'mouse', 'keyboard')

    De manière analogue, la méthode values() renvoie la séquence des valeurs mémorisées dans le dictionnaire :
    >>> print(invent.values()) dict_values([274, 312, 137])

    Quant à la méthode items(), elle extrait du dictionnaire une séquence équivalente de tuples. Cette méthode se révélera très utile plus loin, lorsque nous voudrons parcourir un dictionnaire à l'aide d'une boucle :
    >>> invent.items() dict_items([('poires', 137), ('bananes', 312), ('oranges', 274)]) >>> tuple(invent.items()) (('poires', 137), ('bananes', 312), ('oranges', 274))

    La méthode copy() permet d'effectuer une vraie copie d'un dictionnaire. Il faut savoir en effet que la simple affectation d'un dictionnaire existant à une nouvelle variable crée seulement une nouvelle référence vers le même objet, et non un nouvel objet. Nous avons déjà discuté ce phénomène (aliasing) à propos des listes (voir page ). Par exemple, l'instruction ci-dessous ne définit pas un nouveau dictionnaire (contrairement aux apparences) :
    >>> stock = invent >>> stock {'oranges': 274, 'bananes': 312, 'poires': 137}

    Si nous modifions invent, alors stock est également modifié, et vice-versa (ces deux noms désignent en effet le même objet dictionnaire dans la mémoire de l'ordinateur) :
    >>> del invent['bananes'] >>> stock {'oranges': 274, 'poires': 137}

    Pour obtenir une vraie copie (indépendante) d'un dictionnaire préexistant, il faut employer la méthode copy() :
    >>> magasin = stock.copy() >>> magasin['prunes'] = 561 >>> magasin {'oranges': 274, 'prunes': 561, 'poires': 137} >>> stock {'oranges': 274, 'poires': 137} >>> invent {'oranges': 274, 'poires': 137}

    Vous pouvez utiliser une boucle for pour traiter successivement tous les éléments contenus dans un dictionnaire, mais attention : au cours de l'itération, ce sont les clés utilisées dans le dictionnaire qui seront successivement affectées à la variable de travail, et non les valeurs, l'ordre dans lequel les éléments seront extraits est imprévisible (puisqu'un dictionnaire n'est pas une séquence).
    >>> invent ={"oranges":274, "poires":137, "bananes":312} >>> for clef in invent: ... print(clef) ... poires bananes oranges

    Si vous souhaitez effect uer un traitement sur les valeurs, il vous suffit alors de récupérer chacune d'elles à partir dela clé correspondante :
    >>> for clef in invent: ... print(clef, invent[clef]) ... poires 137 bananes 312 oranges 274

    Cette manière de pr océder n'est cependant pas idéale, ni en termes de performances ni même du point de vue dela lisibilité. Il est recommandé de plutôt faire appel à la méthode items() décrite à la section précédente :
    for clef, valeur in invent.items(): print(clef, valeur) ... poires 137 bananes 312 oranges 274

    Conclusion

    Je n'irais pas plus loin car sinon ce chapitre serait interminable. Si vous souhaitez aller encore plus loin n'hésitez à lire excellente documentation fournie par le site developpez.com et écrite par Gérard Swinnen. J'ai repris les chapitres intéressants de son tutoriel du langage Python.









    Pseudonyme (obligatoire) :
    Adresse mail (obligatoire) :
    Site web :




    © 2017 www.doritique.fr par Robert DORIGNY