cours-python_livret
cours-python_livret
cours-python_livret
https://python.sdv.univ-paris-diderot.fr/ 1 Introduction 9
1.1 C’est quoi Python ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.2 Conseils pour installer et configurer Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
1.3 Notations utilisées . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.4 Introduction au shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10
1.5 Premier contact avec Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11
1.6 Premier programme . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.7 Commentaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
1.8 Notion de bloc d’instructions et d’indentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
1.9 Autres ressources . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
2 Variables 14
2.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.2 Les types de variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
2.3 Nommage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
2.4 Écriture scientifique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Patrick Fuchs et Pierre Poulain 2.5 Opérations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
prénom [point] nom [arobase] u-paris [point] fr 2.6 La fonction type() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.7 Conversion de types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
2.8 Note sur la division de deux nombres entiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.9 Note sur le vocabulaire et la syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.10 Minimum et maximum . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 18
2.11 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
3 Affichage 20
3.1 La fonction print() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
3.2 Écriture formatée . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
3.3 Écriture scientifique . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
version du 1er août 2023
3.4 Ancienne méthode de formatage des chaînes de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
3.5 Note sur le vocabulaire et la syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
3.6 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26
4 Listes 28
Université Paris Cité, France 4.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.2 Utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.3 Opération sur les listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
4.4 Indiçage négatif . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
4.5 Tranches . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
Ce document est sous licence
Creative Commons Attribution - Partage dans les Mêmes Conditions 3.0 France 4.6 Fonction len() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
(CC BY-SA 3.0 FR)
https://creativecommons.org/licenses/by-sa/3.0/fr/
2
Table des matières Table des matières Table des matières Table des matières
4.7 Les fonctions range() et list() . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 10.7 Conversion d’une liste de chaînes de caractères en une chaîne de caractères . . . . . . . . . . . . . . . . . . 82
4.8 Listes de listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 10.8 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
4.9 Minimum, maximum et somme d’une liste . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
4.10 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 11 Plus sur les listes 88
11.1 Méthodes associées aux listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
5 Boucles et comparaisons 33 11.2 Construction d’une liste par itération . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
5.1 Boucles for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
11.3 Test d’appartenance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
5.2 Comparaisons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36
11.4 Copie de listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
5.3 Boucles while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37
5.4 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 11.5 Liste de compréhension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
11.6 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
6 Tests 42
6.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 12 Plus sur les fonctions 96
6.2 Tests à plusieurs cas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 12.1 Appel d’une fonction dans une fonction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96
6.3 Importance de l’indentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 12.2 Fonctions récursives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 97
6.4 Tests multiples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 12.3 Portée des variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98
6.5 Instructions break et continue . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 12.4 Portée des listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99
6.6 Tests de valeur sur des floats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 12.5 Règle LGI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 100
6.7 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 12.6 Recommandations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101
12.7 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
7 Fichiers 50
7.1 Lecture dans un fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50
13 Containers, dictionnaires, tuples et sets 104
7.2 Écriture dans un fichier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52
7.3 Ouvrir deux fichiers avec l’instruction with . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 13.1 Containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104
7.4 Note sur les retours à la ligne sous Unix et sous Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 13.2 Dictionnaires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107
7.5 Importance des conversions de types avec les fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 13.3 Tuples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111
7.6 Du respect des formats de données et de fichiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 13.4 Sets et frozensets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116
7.7 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 13.5 Récapitulation des propriétés des containers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
13.6 Dictionnaires et sets de compréhension . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119
8 Modules 57 13.7 Module collections . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
8.1 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 13.8 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120
8.2 Importation de modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
8.3 Obtenir de l’aide sur les modules importés . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 14 Création de modules 123
8.4 Quelques modules courants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
14.1 Pourquoi créer ses propres modules ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
8.5 Module random : génération de nombres aléatoires . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60
14.2 Création d’un module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
8.6 Module sys : passage d’arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61
14.3 Utilisation de son propre module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
8.7 Module os : interaction avec le système d’exploitation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
8.8 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 14.4 Les docstrings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 124
14.5 Visibilité des fonctions dans un module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
9 Fonctions 66 14.6 Module ou script ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 125
9.1 Principe et généralités . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 66 14.7 Exercice . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126
9.2 Définition . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67
9.3 Passage d’arguments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 15 Bonnes pratiques en programmation Python 127
9.4 Renvoi de résultats . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 15.1 De la bonne syntaxe avec la PEP 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 127
9.5 Arguments positionnels et arguments par mot-clé . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 15.2 Les docstrings et la PEP 257 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131
9.6 Variables locales et variables globales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 15.3 Outils de contrôle qualité du code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133
9.7 Principe DRY . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 15.4 Organisation du code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 134
9.8 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74
15.5 Conseils sur la conception d’un script . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
10 Plus sur les chaînes de caractères 78 15.6 Pour terminer : la PEP 20 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136
10.1 Préambule . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
10.2 Chaînes de caractères et listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78 16 Expressions régulières et parsing 138
10.3 Caractères spéciaux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 16.1 Définition et syntaxe . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138
10.4 Préfixe de chaîne de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79 16.2 Quelques ressources en ligne . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
10.5 Méthodes associées aux chaînes de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 16.3 Le module re . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140
10.6 Extraction de valeurs numériques d’une chaîne de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . 82 16.4 Exercices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 142
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 3 4 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
Table des matières Table des matières Table des matières Table des matières
22 Mini-projets 249
22.1 Description des projets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 249
22.2 Accompagnement pas à pas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 250
22.3 Scripts de correction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 264
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 5 6 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
Table des matières Table des matières
Avant-propos
Remerciements
Un grand merci à Sander 4 du Centre for Molecular and Biomolecular Informatics de Nijmegen aux Pays-Bas pour la
toute première version 5 de ce cours qui remonte à l’année 2003.
Nous remercions le professeur Philip Guo 6 de l’UC San Diego, pour nous avoir autorisé à utiliser des copies d’écran de
son excellent site Python Tutor 7 .
Merci également à tous les contributeurs, occasionels ou réguliers : Jennifer Becq, Virginie Martiny, Romain Laurent,
Benoist Laurent, Benjamin Boyer, Hubert Santuz, Catherine Lesourd, Philippe Label, Rémi Cuchillo, Cédric Gageat, Philibert
Malbranche, Mikaël Naveau, Amélie Bacle, Alexandra Moine-Franel.
Nous remercions aussi Denis Mestivier de qui nous nous sommes inspirés pour certains exercices.
Enfin, merci à vous tous, les curieux de Python, qui avez été nombreux à nous envoyer des retours sur ce cours, à nous
suggérer des améliorations et à nous signaler des coquilles.
De nombreuses personnes nous ont aussi demandé les corrections des exercices. Nous ne les mettons pas sur le site afin
d’éviter la tentation de les regarder trop vite, mais vous pouvez nous écrire et nous vous les enverrons.
F IGURE 1 – Couverture livre Dunod.
Le livre
Ce cours est également publié aux éditions Dunod sous le titre « Programmation en Python pour les sciences de la vie 8 ».
Vous pouvez vous le procurer dans toutes les bonnes librairies.
Afin de promouvoir le partage des connaissances et le logiciel libre, nos droits d’auteurs provenant de la vente de cet
ouvrage seront reversés à deux associations. Wikimédia France 9 qui s’occupe notamment de l’encyclopédie libre Wikipédia.
NumFOCUS 10 qui soutient le développement de logiciels libres scientifiques et notamment l’écosystème scientifique autour
de Python.
1. https://www.u-paris.fr/
2. https://python.sdv.univ-paris-diderot.fr/index.html
3. https://python.sdv.univ-paris-diderot.fr/cours-python.pdf
4. http://sander.nabuurs.org/
5. http://www.cmbi.ru.nl/pythoncourse/spy/index.spy?site=python&action=Home
6. http://pgbovine.net/
7. http://pythontutor.com/
8. https://www.dunod.com/sciences-techniques/programmation-en-python-pour-sciences-vie
9. https://www.wikimedia.fr/
10. https://numfocus.org/
Si, néanmoins, vous deviez un jour travailler sur un ancien programme écrit en Python 2, sachez qu’il existe quelques
différences importantes entre Python 2 et Python 3. Le chapitre 21 Remarques complémentaires vous apportera plus de préci-
sions.
1.2.2 Miniconda
Chapitre 1 Nous vous conseillons d’installer Miniconda 3 , logiciel gratuit, disponible pour Windows, Mac OS X et Linux, et qui
installera pour vous Python 3.
Avec le gestionnaire de paquets conda, fourni avec Miniconda, vous pourrez installer des modules supplémentaires qui
sont très utiles en bioinformatique (NumPy, scipy, matplotlib, pandas, Biopython), mais également Jupyter Lab qui vous
Introduction permettra d’éditer des notebooks Jupyter. Vous trouverez en ligne 4 une documentation pas-à-pas pour installer Miniconda,
Python 3 et les modules supplémentaires qui seront utilisés dans ce cours.
1.5 Premier contact avec Python 1 >>> Voici une ligne de code qui \
2 ... est vraiment tr è s longue car \
3 ... elle est d é coup é e sur trois lignes
Python est un langage interprété, c’est-à-dire que chaque ligne de code est lue puis interprétée afin d’être exécutée par 4 r é sultat
l’ordinateur. Pour vous en rendre compte, ouvrez un shell puis lancez la commande :
python L’interpréteur Python est donc un système interactif dans lequel vous pouvez entrer des commandes, que Python exécutera
La commande précédente va lancer l’interpréteur Python. Vous devriez obtenir quelque chose de ce style pour Windows : sous vos yeux (au moment où vous validerez la commande en appuyant sur la touche Entrée).
1 PS C :\ Users \ pierre > python Il existe de nombreux autres langages interprétés comme Perl 8 ou R 9 . Le gros avantage de ce type de langage est qu’on
2 Python 3.7.1 ( default , Dec 10 2018 , 22:54:23) [ MSC v .1915 64 bit ( AMD64 )] [...] peut immédiatement tester une commande à l’aide de l’interpréteur, ce qui est très utile pour débugger (c’est-à-dire trouver et
3 Type " help " , " copyright " , " credits " or " license " for more information .
4 >>> corriger les éventuelles erreurs d’un programme). Gardez bien en mémoire cette propriété de Python qui pourra parfois vous
faire gagner un temps précieux !
pour Mac OS X :
1 iMac - de - pierre : Downloads$ python
2 Python 3.7.1 ( default , Dec 14 2018 , 19:28:38)
3 [ Clang 4.0.1 ( tags / RELEASE_401 / final )] :: Anaconda , Inc . on darwin 1.6 Premier programme
4 Type " help " , " copyright " , " credits " or " license " for more information .
5 >>>
Bien sûr, l’interpréteur présente vite des limites dès lors que l’on veut exécuter une suite d’instructions plus complexe.
ou pour Linux : Comme tout langage informatique, on peut enregistrer ces instructions dans un fichier, que l’on appelle communément un
1 pierre@jeera :~ $ python script (ou programme) Python.
2 Python 3.7.1 ( default , Dec 14 2018 , 19:28:38)
3 [ GCC 7.3.0] :: Anaconda , Inc . on linux
Pour reprendre l’exemple précédent, ouvrez un éditeur de texte (pour choisir et configurer un éditeur de texte, reportez-
4 Type " help " , " copyright " , " credits " or " license " for more information . vous si nécessaire à la rubrique Installation de Python en ligne 10 ) et entrez le code suivant :
>>>
print("Hello world!")
5
Les blocs Ensuite, enregistrez votre fichier sous le nom test.py, puis quittez l’éditeur de texte.
— PS C:\Users\pierre> pour Windows,
— iMac-de-pierre:Downloads$ pour Mac OS X, Remarque
— pierre@jeera:~$ pour Linux. L’extension de fichier standard des scripts Python est .py.
représentent l’invite de commande de votre shell. Par la suite, cette invite de commande sera représentée simplement par
le caractère $, que vous soyez sous Windows, Mac OS X ou Linux.
Le triple chevron >>> est l’invite de commande (prompt en anglais) de l’interpréteur Python. Ici, Python attend une Pour exécuter votre script, ouvrez un shell et entrez la commande :
commande que vous devez saisir au clavier. Tapez par exemple l’instruction : python test.py
print("Hello world!") Vous devriez obtenir un résultat similaire à ceci :
puis validez cette commande en appuyant sur la touche Entrée.
$ python test . py
Python a exécuté la commande directement et a affiché le texte Hello world!. Il attend ensuite une nouvelle instruction 1
2 Hello world !
en affichant l’invite de l’interpréteur Python (>>>). En résumé, voici ce qui a dû apparaître sur votre écran :
1 >>> print (" Hello world !") Si c’est bien le cas, bravo ! Vous avez exécuté votre premier programme Python.
2 Hello world !
3 >>>
Vous pouvez refaire un nouvel essai en vous servant cette fois de l’interpréteur comme d’une calculatrice : 1.7 Commentaires
1 >>> 1+1
2 2
3 >>> 6*3 Dans un script, tout ce qui suit le caractère # est ignoré par Python jusqu’à la fin de la ligne et est considéré comme un
4 18
commentaire.
À ce stade, vous pouvez entrer une autre commande ou bien quitter l’interpréteur Python, soit en tapant la commande Les commentaires doivent expliquer votre code dans un langage humain. L’utilisation des commentaires est rediscutée
exit() puis en validant en appuyant sur la touche Entrée, soit en pressant simultanément les touches Ctrl et D sous Linux et dans le chapitre 15 Bonnes pratiques en programmation Python.
Mac OS X ou Ctrl et Z puis Entrée sous Windows. Voici un exemple :
En résumant, l’interpréteur fonctionne sur le modèle : 1 # Votre premier commentaire en Python .
1 >>> instruction python 2 print (" Hello world !")
2 r é sultat 3
4 # D ' autres commandes plus utiles pourraient suivre .
où le triple chevron correspond à l’entrée (input) que l’utilisateur tape au clavier, et l’absence de chevron en début de ligne
correspond à la sortie (output) générée par Python. Une exception se présente toutefois : lorsqu’on a une longue ligne de code,
on peut la couper en deux avec le caractère \ (backslash) pour des raisons de lisibilité : Remarque
1 >>> Voici une longue ligne de code \ On appelle souvent à tort le caractère # « dièse ». On devrait plutôt parler de « croisillon 11 ».
2 ... d é crite sur deux lignes
3 r é sultat
En ligne 1 on a rentré la première partie de la ligne de code. On termine par un \, ainsi Python sait que la ligne de code
8. http://www.perl.org
n’est pas finie. L’interpréteur nous l’indique avec les .... En ligne 2, on rentre la fin de la ligne de code puis on appuie sur 9. http://www.r-project.org
Entrée. A ce moment, Python nous génère le résultat. Si la ligne de code est vraiment très longue, il est même possible de la 10. https://python.sdv.univ-paris-diderot.fr/livre-dunod
découper en trois voire plus : 11. https://fr.wikipedia.org/wiki/Croisillon_(signe)
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 11 12 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
1.8. Notion de bloc d’instructions et d’indentation Chapitre 1. Introduction
Chapitre 2
Variables
F IGURE 1.1 – Notion d’indentation et de bloc d’instructions.
2.1 Définition
1.8 Notion de bloc d’instructions et d’indentation
Une variable est une zone de la mémoire de l’ordinateur dans laquelle une valeur est stockée. Aux yeux du programmeur,
En programmation, il est courant de répéter un certain nombre de choses (avec les boucles, voir le chapitre 5 Boucles et cette variable est définie par un nom, alors que pour l’ordinateur, il s’agit en fait d’une adresse, c’est-à-dire d’une zone
comparaisons) ou d’exécuter plusieurs instructions si une condition est vraie (avec les tests, voir le chapitre 6 Tests). particulière de la mémoire.
Par exemple, imaginons que nous souhaitions afficher chacune des bases d’une séquence d’ADN, les compter puis afficher En Python, la déclaration d’une variable et son initialisation (c’est-à-dire la première valeur que l’on va stocker dedans)
le nombre total de bases à la fin. Nous pourrions utiliser l’algorithme présenté en pseudo-code dans la figure 1.1. se font en même temps. Pour vous en convaincre, testez les instructions suivantes après avoir lancé l’interpréteur :
Pour chaque base de la séquence ATCCGACTG, nous souhaitons effectuer deux actions : d’abord afficher la base puis
1 >>> x = 2
compter une base de plus. Pour indiquer cela, on décalera vers la droite ces deux instructions par rapport à la ligne précédente 2 >>> x
(pour chaque base [...]). Ce décalage est appelé indentation, et l’ensemble des lignes indentées constitue un bloc 3 2
d’instructions. Ligne 1. Dans cet exemple, nous avons déclaré, puis initialisé la variable x avec la valeur 2. Notez bien qu’en réalité, il
Une fois qu’on aura réalisé ces deux actions sur chaque base, on pourra passer à la suite, c’est-à-dire afficher la taille de s’est passé plusieurs choses :
la séquence. Pour bien préciser que cet affichage se fait à la fin, donc une fois l’affichage puis le comptage de chaque base — Python a « deviné » que la variable était un entier. On dit que Python est un langage au typage dynamique.
terminés, la ligne correspondante n’est pas indentée (c’est-à-dire qu’elle n’est pas décalée vers la droite). — Python a alloué (réservé) l’espace en mémoire pour y accueillir un entier. Chaque type de variable prend plus ou moins
Pratiquement, l’indentation en Python doit être homogène (soit des espaces, soit des tabulations, mais pas un mélange d’espace en mémoire. Python a aussi fait en sorte qu’on puisse retrouver la variable sous le nom x.
des deux). Une indentation avec 4 espaces est le style d’indentation recommandé (voir le chapitre 15 Bonnes pratiques en — Enfin, Python a assigné la valeur 2 à la variable x.
programmation Python). Dans d’autres langages (en C par exemple), il faut coder ces différentes étapes une par une. Python étant un langage dit de
Si tout cela semble un peu complexe, ne vous inquiétez pas. Vous allez comprendre tous ces détails chapitre après chapitre. haut niveau, la simple instruction x = 2 a suffi à réaliser les 3 étapes en une fois !
Lignes 2 et 3. L’interpréteur nous a permis de connaître le contenu de la variable juste en tapant son nom. Retenez ceci
car c’est une spécificité de l’interpréteur Python, très pratique pour chasser (debugger) les erreurs dans un programme. Par
1.9 Autres ressources contre, la ligne d’un script Python qui contient seulement le nom d’une variable (sans aucune autre indication) n’affichera pas
Pour compléter votre apprentissage de Python, n’hésitez pas à consulter d’autres ressources complémentaires à cet ou- la valeur de la variable à l’écran lors de l’exécution (pour autant, cette instruction reste valide et ne générera pas d’erreur).
vrage. D’autres auteurs abordent l’apprentissage de Python d’une autre manière. Nous vous conseillons les ressources sui- Sachez par ailleurs que l’opérateur d’affectation = s’utilise dans un certain sens. Par exemple, l’instruction x = 2 signifie
vantes en langue française : qu’on attribue la valeur située à droite de l’opérateur = (ici, 2) à la variable située à gauche (ici, x). D’autres langages de
— Le livre Apprendre à programmer avec Python 3 de Gérard Swinnen. Cet ouvrage est téléchargeable gratuitement sur programmation comme R utilisent les symboles <- pour rendre l’affectation d’une variable plus explicite, par exemple x <-
le site de Gérard Swinnen 12 . Les éditions Eyrolles proposent également la version papier de cet ouvrage. 2.
— Le livre Apprendre à programmer en Python avec PyZo et Jupyter Notebook de Bob Cordeau et Laurent Pointal, publié Enfin, dans l’instruction x = y - 3, l’opération y - 3 est d’abord évaluée et ensuite le résultat de cette opération est
aux éditions Dunod. Une partie de cet ouvrage est téléchargeable gratuitement sur le site de Laurent Pointal 13 . affecté à la variable x.
— Le livre Apprenez à programmer en Python de Vincent Legoff 14 que vous trouverez sur le site Openclassroms.
Et pour terminer, une ressource incontournable en langue anglaise :
— Le site www.python.org 15 . Il contient énormément d’informations et de liens sur Python. La page d’index des mo- 2.2 Les types de variables
dules 16 est particulièrement utile (et traduite en français).
Le type d’une variable correspond à la nature de celle-ci. Les trois principaux types dont nous aurons besoin dans un
premier temps sont les entiers (integer ou int), les nombres décimaux que nous appellerons floats et les chaînes de caractères
(string ou str). Bien sûr, il existe de nombreux autres types (par exemple, les booléens, les nombres complexes, etc.). Si vous
n’êtes pas effrayés, vous pouvez vous en rendre compte ici 1 .
12. http://www.inforef.be/swi/python.htm Dans l’exemple précédent, nous avons stocké un nombre entier (int) dans la variable x, mais il est tout à fait possible de
13. https://perso.limsi.fr/pointal/python:courspython3 stocker des floats, des chaînes de caractères (string ou str) ou de nombreux autres types de variable que nous verrons par la
14. https://openclassrooms.com/fr/courses/235344-apprenez-a-programmer-en-python suite :
15. http://www.python.org
16. https://docs.python.org/fr/3/py-modindex.html 1. https://docs.python.org/fr/3.7/library/stdtypes.html
7 >>> 8 % 4
On peut écrire des nombres très grands ou très petits avec des puissances de 10 en utilisant le symbole e : 8 0
>>> 1 e6
1
2 1000000.0 Les symboles +, -, *, /, **, // et % sont appelés opérateurs, car ils réalisent des opérations sur les variables.
3 >>> 3.12 e -3 Enfin, il existe des opérateurs « combinés » qui effectue une opération et une affectation en une seule étape :
4 0.00312
1 >>> i = 0
On appelle cela écriture ou notation scientifique. On pourra noter deux choses importantes : 2 >>> i = i + 1
3 >>> i
— 1e6 ou 3.12e-3 n’implique pas l’utilisation du nombre exponentiel e mais signifie 1 × 106 ou 3.12 × 10−3 respecti- 4 1
vement ; 5 >>> i += 1
6 >>> i
— Même si on ne met que des entiers à gauche et à droite du symbole e (comme dans 1e6), Python génère systématique- 7 2
8 >>> i += 2
ment un float. 9 >>> i
Enfin, vous avez sans doute constaté qu’il est parfois pénible d’écrire des nombres composés de beaucoup de chiffres, par 10 4
exemple le nombre d’Avogradro 6.02214076 × 1023 ou le nombre d’humains sur Terre (au 26 août 2020) 7807568245. Pour L’opérateur += effectue une addition puis affecte le résultat à la même variable. Cette opération s’appelle une « incrémen-
s’y retrouver, Python autorise l’utilisation du caractère « souligné » (ou underscore) _ pour séparer des groupes de chiffres. tation ».
Par exemple : Les opérateurs -=, *= et /= se comportent de manière similaire pour la soustraction, la multiplication et la division.
1 >>> avogadro_ numbe r = 6.022 _140_76e23
2 >>> print ( avoga dro_n umbe r )
6.02214076 e +23
3
4 >>> humans_on _eart h = 7 _807_568_245 2.5.2 Opérations sur les chaînes de caractères
5 >>> print ( human s_on_ eart h )
6 7807568245 Pour les chaînes de caractères, deux opérations sont possibles, l’addition et la multiplication :
Dans ces exemples, le caractère _ est utilisé pour séparer des groupes de 3 chiffres mais on peut faire ce qu’on veut : 2. https://fr.wikipedia.org/wiki/Division_euclidienne
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 15 16 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
2.6. La fonction type() Chapitre 2. Variables Chapitre 2. Variables 2.8. Note sur la division de deux nombres entiers
Attention
Vous observez que les opérateurs + et * se comportent différemment s’il s’agit d’entiers ou de chaînes de caractères : 2 2.8 Note sur la division de deux nombres entiers
+ 2 est une addition alors que "2" + "2" est une concaténation. On appelle ce comportement redéfinition des opérateurs.
Nous serons amenés à revoir cette notion dans le chapitre 19 Avoir la classe avec les objets. Notez bien qu’en Python 3, la division de deux nombres entiers renvoie par défaut un float :
1 >>> x = 3 / 4
2 >>> x
3 0.75
4 >>> type ( x )
5 < class ' float ' >
2.5.3 Opérations illicites
Attention à ne pas faire d’opération illicite car vous obtiendriez un message d’erreur :
Remarque
1 >>> " toto " * 1.3
2 Traceback ( most recent call last ):
Ceci n’était pas le cas en Python 2. Pour en savoir plus sur ce point, vous pouvez consulter le chapitre 21 Remarques
3 File " < stdin >" , line 1 , in < module > complémentaires.
4 TypeError : can ' t multiply sequence by non - int of type ' float '
5 >>> " toto " + 2
6 Traceback ( most recent call last ):
7 File " < stdin >" , line 1 , in < module >
8 TypeError : can only concatenate str ( not " int ") to str
Notez que Python vous donne des informations dans son message d’erreur. Dans le second exemple, il indique que vous 2.9 Note sur le vocabulaire et la syntaxe
devez utiliser une variable de type str c’est-à-dire une chaîne de caractères et pas un int, c’est-à-dire un entier.
Nous avons vu dans ce chapitre la notion de variable qui est commune à tous les langages de programmation. Toutefois,
Python est un langage dit « orienté objet », il se peut que dans la suite du cours nous employions le mot objet pour désigner
2.6 La fonction type() une variable. Par exemple, « une variable de type entier » sera pour nous équivalent à « un objet de type entier ». Nous verrons
dans le chapitre 19 Avoir la classe avec les objets ce que le mot « objet » signifie réellement (tout comme le mot « classe »).
Si vous ne vous souvenez plus du type d’une variable, utilisez la fonction type() qui vous le rappellera. Par ailleurs, nous avons rencontré plusieurs fois des fonctions dans ce chapitre, notamment avec type(), int(), float()
1 >>> x = 2
et str(). Dans le chapitre 1 Introduction, nous avons également vu la fonction print(). On reconnaît qu’il s’agit d’une
2 >>> type ( x ) fonction car son nom est suivi de parenthèses (par exemple, type()). En Python, la syntaxe générale est fonction().
3 < class 'int ' > Ce qui se trouve entre les parenthèses d’une fonction est appelé argument et c’est ce que l’on « passe » à la fonction.
4 >>> y = 2.0
5 >>> type ( y ) Dans l’instruction type(2), c’est l’entier 2 qui est l’argument passé à la fonction type(). Pour l’instant, on retiendra qu’une
6 < class ' float ' > fonction est une sorte de boîte à qui on passe un (ou plusieurs) argument(s), qui effectue une action et qui peut renvoyer un
7 >>> z = '2 '
8 >>> type ( z ) résultat ou plus généralement un objet. Par exemple, la fonction type() renvoie le type de la variable qu’on lui a passé en
9 < class 'str ' > argument.
Nous verrons plus tard ce que signifie le mot class. Si ces notions vous semblent obscures, ne vous inquiétez pas, au fur et à mesure que vous avancerez dans le cours, tout
deviendra limpide.
Attention
Pour Python, la valeur 2 (nombre entier) est différente de 2.0 (float) et est aussi différente de '2' (chaîne de caractères). 2.10 Minimum et maximum
Python propose les fonctions min() et max() qui renvoient respectivement le minimum et le maximum de plusieurs entiers
et / ou floats :
2.7 Conversion de types 1 >>> min (1 , -2 , 4)
2 -2
3 >>> pi = 3.14
En programmation, on est souvent amené à convertir les types, c’est-à-dire passer d’un type numérique à une chaîne 4 >>> e = 2.71
5 >>> max (e , pi )
de caractères ou vice-versa. En Python, rien de plus simple avec les fonctions int(), float() et str(). Pour vous en 6 3.14
convaincre, regardez ces exemples : 7 >>> max (1 , 2.4 , -6)
8 2.4
1 >>> i = 3
2 >>> str ( i ) Par rapport à la discussion de la rubrique précédente, min() et max() sont des exemples de fonction prenant plusieurs
'3 '
3
4 >>> i = '456 ' arguments. En Python, quand une fonction prend plusieurs arguments, on doit les séparer par une virgule. min() et max()
5 >>> int ( i ) prennent en argument autant d’entiers et de floats que l’on veut, mais il en faut au moins deux.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 17 18 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
2.11. Exercices Chapitre 2. Variables
2.11 Exercices
Conseil : utilisez l’interpréteur Python pour les exercices suivants.
— ("Da"*4) / 2 Ligne 1. On a utilisé l’instruction print() classiquement en passant la chaîne de caractères "Hello world!" en argu-
— 5 / 2 ment.
— 5 // 2 Ligne 3. On a ajouté un second argument end="", en précisant le mot-clé end. Nous aborderons les arguments par mot-clé
— 5 % 2 dans le chapitre 9 Fonctions. Pour l’instant, dites-vous que cela modifie le comportement par défaut des fonctions.
Ligne 4. L’effet de l’argument end="" est que les trois chevrons >>> se retrouvent collés après la chaîne de caractères
2.11.3 Prédire le résultat : opérations et conversions de types "Hello world!".
Une autre manière de s’en rendre compte est d’utiliser deux fonctions print() à la suite. Dans la portion de code suivante,
Essayez de prédire le résultat de chacune des instructions suivantes, puis vérifiez-le dans l’interpréteur Python : le caractère « ; » sert à séparer plusieurs instructions Python sur une même ligne :
— str(4) * int("3") 1 >>> print (" Hello ") ; print (" Joe ")
— int("3") + float("3.2") 2 Hello
Joe
— str(3) * float("3.2") 3
4 >>> print (" Hello " , end ="") ; print (" Joe ")
— str(3/4) * 2 5 HelloJoe
6 >>> print (" Hello " , end =" ") ; print (" Joe ")
7 Hello Joe
La fonction print() peut également afficher le contenu d’une variable quel que soit son type. Par exemple, pour un
entier :
1 >>> var = 3
2 >>> print ( var )
3 3
Il est également possible d’afficher le contenu de plusieurs variables (quel que soit leur type) en les séparant par des
virgules :
1 >>> x = 32
2 >>> nom = " John "
3 >>> print ( nom , " a " , x , " ans ")
4 John a 32 ans
Python a écrit une phrase complète en remplaçant les variables x et nom par leur contenu. Vous remarquerez que pour
afficher plusieurs éléments de texte sur une seule ligne, nous avons utilisé le séparateur « , » entre les différents éléments.
Python a également ajouté un espace à chaque fois que l’on utilisait le séparateur « , ». On peut modifier ce comportement en
passant à la fonction print() l’argument par mot-clé sep :
1 >>> x = 32
2 >>> nom = " John "
3. https://fr.wikipedia.org/wiki/Nombre_de_Friedman 3 >>> print ( nom , " a " , x , " ans " , sep ="")
4 Johna32ans Il suffit de passer un nom de variable au sein de chaque couple d’accolades et Python les remplace par leur contenu !
5 >>> print ( nom , " a " , x , " ans " , sep =" -") Première remarque, la syntaxe apparait plus lisible que l’équivalent vu ci-avant print(nom, "a", x, "ans"). Bien sûr, il
6 John -a -32 - ans
ne faut pas omettre le f avant le premier guillemet, sinon Python prendra cela pour une chaîne de caractères normale et ne
Pour afficher deux chaînes de caractères l’une à côté de l’autre, sans espace, on peut soit les concaténer, soit utiliser mettra pas en place ce mécanisme de remplacement :
l’argument par mot-clé sep avec une chaîne de caractères vide : 1 >>> print ("{ nom } a { x } ans ")
1 >>> ani1 = " chat " 2 { nom } a { x } ans
2 >>> ani2 = " souris "
3 >>> print ( ani1 , ani2 )
4 chat souris
5 >>> print ( ani1 + ani2 ) Remarque
6 chatsouris Une variable est utilisable plus d’une fois pour une f-string donnée :
7 >>> print ( ani1 , ani2 , sep ="")
8 chatsouris 1 >>> var = " to "
2 >>> print ( f "{ var } et { var } font { var }{ var }")
3 to et to font toto
4 >>>
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 21 22 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
3.2. Écriture formatée Chapitre 3. Affichage Chapitre 3. Affichage 3.3. Écriture scientifique
Notez que > spécifie un alignement à droite, < spécifie un alignement à gauche et ˆ spécifie un alignement centré. Il
est également possible d’indiquer le caractère qui servira de remplissage lors des alignements (l’espace est le caractère par 3.3 Écriture scientifique
défaut).
Pour les nombres très grands ou très petits, l’écriture formatée permet d’afficher un nombre en notation scientifique (sous
Ce formatage est également possible sur des chaînes de caractères avec la lettre s (comme string) :
forme de puissance de 10) avec la lettre e :
1 >>> print (" atom HN ") ; print (" atom HDE1 ")
2 atom HN 1 >>> print ( f "{1 _000_000_000 : e }")
3 atom HDE1 2 1.000000 e +09
4 >>> print ( f " atom { ' HN ': >4 s }") ; print ( f " atom { ' HDE1 ': >4 s }") 3 >>> print ( f "{0.000 _000_001 : e }")
5 atom HN 4 1.000000 e -09
6 atom HDE1
Il est également possible de définir le nombre de chiffres après la virgule. Dans l’exemple ci-dessous, on affiche un nombre
Vous voyez tout de suite l’énorme avantage de l’écriture formatée. Elle vous permet d’écrire en colonnes parfaitement avec aucun, 3 et 6 chiffres après la virgule :
alignées. Nous verrons que ceci est très pratique si l’on veut écrire les coordonnées des atomes d’une molécule au format PDB 1 >>> avogadro_nu m be r = 6.022 _140_76e23
(pour en savoir plus sur ce format, reportez-vous à l’annexe A Quelques formats de données rencontrés en biologie). 2 >>> print ( f "{ av og ad r o_ nu mb er :.0 e }")
3 6 e +23
Pour les floats, il est possible de combiner le nombre de caractères à afficher avec le nombre de décimales : 4 >>> print ( f "{ av og ad r o_ nu mb er :.3 e }")
1 >>> print ( f "{ perc_GC :7.3 f }") 5 6.022 e +23
2 47.804 6 >>> print ( f "{ av og ad r o_ nu mb er :.6 e }")
3 >>> print ( f "{ perc_GC :10.3 f }") 7 6.022141 e +23
4 47.804
L’instruction 7.3f signifie que l’on souhaite écrire un float avec 3 décimales et formaté sur 7 caractères (par défaut justifiés
à droite). L’instruction 10.3f fait la même chose sur 10 caractères. Remarquez que le séparateur décimal . compte pour un 3.4 Ancienne méthode de formatage des chaînes de caractères
caractère. De même, si on avait un nombre négatif, le signe - compterait aussi pour un caractère.
Conseil : Pour les débutants, tout ce qui est écrit dans cette rubrique n’est pas à retenir.
Dans les premières versions de Python jusqu’à la 2.6, il fallait utiliser l’opérateur %, puis de la version 2.7 jusqu’à la 3.5 il
3.2.4 Autres détails sur les f-strings était plutôt conseillé d’utiliser la méthode .format() (voir la rubrique suivante pour la définition du mot « méthode »). Même
Si on veut afficher des accolades littérales avec les f-strings, il faut les doubler pour échapper au formatage : si les f-strings sont devenues la manière conseillée pour mettre en place l’écriture formatée, ces deux anciennes manières, sont
1 >>> print ( f " Accolades litt é rales {{}} ou {{ ou }} et pour le formatage {10}") encore pleinement compatibles avec les versions modernes de Python.
2 Accolades litt é rales {} ou { ou } et pour le formatage 10 Même si elle fonctionne encore, la première manière avec l’opérateur % est maintenant clairement déconseillée pour un
certain nombre de raisons 2 . Néanmoins, nous rappelons ci-dessous son fonctionnement, car il se peut que vous tombiez dessus
Une remarque importante, si on ne met pas de variable à formater entre les accolades dans une f-string, cela conduit à une
dans d’anciens livres ou si vous lisez de vieux programmes Python.
erreur :
La deuxième manière avec la méthode .format() est encore largement utilisée et reste tout à fait valide. Elle est clai-
1 >>> print ( f " accolades sans variable {}")
2 File " < stdin >" , line 1 rement plus puissante et évite un certain nombre de désagréments par rapport à l’opérateur %. Vous la croiserez sans doute
3 SyntaxError : f - string : empty expression not allowed très fréquemment dans des programmes et ouvrages récents. Heureusement elle a un fonctionnement relativement proche des
Enfin, il est important de bien comprendre qu’une f-string est indépendante de la fonction print(). Si on donne une f-strings, donc vous ne serez pas totalement perdus !
f-string à la fonction print(), Python évalue d’abord la f-string et c’est la chaîne de caractères qui en résulte qui est affichée Enfin, nous indiquons à la fin de cette rubrique nos conseils sur quelle méthode utiliser.
à l’écran. Tout comme dans l’instruction print(5*5), c’est d’abord la multiplication (5*5) qui est évaluée, puis son résultat 1. https://fstring.help/cheat/
qui est affiché à l’écran. On peut s’en rendre compte de la manière suivante dans l’interpréteur : 2. https://docs.python.org/fr/3/library/stdtypes.html?highlight=sprintf#printf-style-string-formatting
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 23 24 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
3.4. Ancienne méthode de formatage des chaînes de caractères Chapitre 3. Affichage Chapitre 3. Affichage 3.5. Note sur le vocabulaire et la syntaxe
3.4.1 L’opérateur % Enfin, si vous souhaitez aller plus loin, voici deux articles (en anglais) très bien faits sur le site RealPython : sur l’écriture
formatée 3 et sur les f-strings 4
On a vu avec les entiers que l’opérateur % ou modulo renvoyait le reste d’une division entière. Cet opérateur existe aussi
pour les chaînes de caractères mais il met en place l’écriture formatée. En voici un exemple :
1 >>> x = 32
2 >>> nom = " John "
3 >>> print ("% s a % d ans " % ( nom , x ))
4 John a 32 ans 3.5 Note sur le vocabulaire et la syntaxe
5 >>> nb_G = 4500
6 >>> nb_C = 2575
7 >>> prop_GC = ( nb_G + nb_C )/14800 Revenons quelques instants sur la notion de méthode abordée dans ce chapitre avec .format(). En Python, on peut
8 >>> print (" On a % d G et % d C -> prop GC = %.2 f " % ( nb_G , nb_C , prop_GC )) considérer chaque variable comme un objet sur lequel on peut appliquer des méthodes. Une méthode est simplement une
9 On a 4500 G et 2575 C -> prop GC = 0.48
fonction qui utilise et/ou agit sur l’objet lui-même, les deux étant connectés par un point. La syntaxe générale est de la forme
La syntaxe est légèrement différente. Le symbole % est d’abord appelé dans la chaîne de caractères (dans l’exemple ci- objet.méthode().
dessus %d, %d et %.2f) pour : Dans l’exemple suivant :
— Désigner l’endroit où sera placée la variable dans la chaîne de caractères. 1 >>> " Joe a {} ans ". format (20)
— Préciser le type de variable à formater, d pour un entier (i fonctionne également) ou f pour un float. 2 ' Joe a 20 ans '
— Éventuellement pour indiquer le format voulu. Ici .2 signifie une précision de deux décimales.
la méthode .format() est liée à "Joe a {} ans" qui est un objet de type chaîne de caractères. La méthode renvoie une
Le signe % est rappelé une seconde fois (% (nb_G, nb_C, prop_GC)) pour indiquer les variables à formater.
nouvelle chaîne de caractères avec le bon formatage (ici, 'Joe a 20 ans').
Nous aurons de nombreuses occasions de revoir cette notation objet.méthode().
3.4.2 La méthode .format()
Depuis la version 2.7 de Python, la méthode .format() (voir la rubrique suivante pour la définition d’une méthode) a 3.6 Exercices
apporté une nette amélioration pour mettre en place l’écriture formatée. Celle-ci fonctionne de la manière suivante :
1 >>> x = 32 Conseil : utilisez l’interpréteur Python pour les exercices 2 à 5.
2 >>> nom = " John "
3 >>> print ("{} a {} ans ". format ( nom , x ))
4 John a 32 ans
5 >>> nb_G = 4500 3.6.1 Affichage dans l’interpréteur et dans un programme
6 >>> nb_C = 2575
7 >>> prop_GC = ( nb_G + nb_C )/14800 Ouvrez l’interpréteur Python et tapez l’instruction 1+1. Que se passe-t-il ?
8 >>> print (" On a {} G et {} C -> prop GC = {:.2 f }". format ( nb_G , nb_C , prop_GC ))
9 On a 4500 G et 2575 C -> prop GC = 0.48 Écrivez la même chose dans un script test.py que vous allez créer avec un éditeur de texte. Exécutez ce script en
tapant python test.py dans un shell. Que se passe-t-il ? Pourquoi ? Faites en sorte d’afficher le résultat de l’addition 1+1 en
— Dans la chaîne de caractères, les accolades vides {} précisent l’endroit où le contenu de la variable doit être inséré. exécutant le script dans un shell.
— Juste après la chaîne de caractères, l’instruction .format(nom, x) fournit la liste des variables à insérer, d’abord la
variable nom puis la variable x.
— On peut éventuellement préciser le formatage en mettant un caractère deux-points : puis par exemple ici .2f qui 3.6.2 Poly-A
signifie 2 chiffres après la virgule.
Générez une chaîne de caractères représentant un brin d’ADN poly-A (c’est-à-dire qui ne contient que des bases A) de 20
— La méthode .format() agit sur la chaîne de caractères à laquelle elle est attachée par le point.
bases de longueur, sans taper littéralement toutes les bases.
Tout ce que nous avons vu avec les f-strings sur la manière de formatter l’affichage d’une variable (après les : au sein
des accolades) est identique avec la méthode .format(). Par exemple {:.2f}, {:0>6d}, {:.6e}, etc., fonctionneront de la
même manière. La différence notable est qu’on ne met pas directement le nom de la variable au sein des accolades. Comme 3.6.3 Poly-A et poly-GC
pour l’opérateur %, c’est l’emplacement dans les arguments passés à la méthode .format() qui dicte quelle variable doit
être remplacée. Par exemple, dans "{} {} {}".format(bidule, machin, truc), les premières accolades remplaceront Sur le modèle de l’exercice précédent, générez en une ligne de code un brin d’ADN poly-A (AAAA. . . ) de 20 bases suivi
la variable bidule, les deuxièmes la variable machin, les troisièmes la variable truc. d’un poly-GC régulier (GCGCGC. . . ) de 40 bases.
Le formattage avec la méthode .format() se rapproche de la syntaxe des f-strings (accolades, deux-points), mais présente
l’inconvénient – comme avec l’opérateur % – de devoir mettre la liste des variables tout à la fin, alourdissant ainsi la syntaxe. 3.6.4 Écriture formatée
En effet, dans l’exemple avec la proportion de GC, la ligne équivalente avec une f-string apparait tout de même plus simple à
lire : En utilisant l’écriture formatée, affichez en une seule ligne les variables a, b et c dont les valeurs sont respectivement la
1 >>> print ( f " On a { nb_G } G et { nb_C } C -> prop GC = { prop_GC :.2 f }") chaîne de caractères "salut", le nombre entier 102 et le float 10.318. La variable c sera affichée avec 2 décimales.
2 On a 4500 G et 2575 C -> prop GC = 0.48
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 25 26 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
3.6. Exercices Chapitre 3. Affichage
1 Le pourcentage de GC est 48 %
2 Le pourcentage de GC est 47.8 %
3 Le pourcentage de GC est 47.80 %
4 Le pourcentage de GC est 47.804 %
Chapitre 4
Listes
4.1 Définition
Une liste est une structure de données qui contient une série de valeurs. Python autorise la construction de liste contenant
des valeurs de types différents (par exemple entier et chaîne de caractères), ce qui leur confère une grande flexibilité. Une liste
est déclarée par une série de valeurs (n’oubliez pas les guillemets, simples ou doubles, s’il s’agit de chaînes de caractères)
séparées par des virgules, et le tout encadré par des crochets. En voici quelques exemples :
1 >>> animaux = [" girafe " , " tigre " , " singe " , " souris "]
2 >>> tailles = [5 , 2.5 , 1.75 , 0.15]
3 >>> mixte = [" girafe " , 5 , " souris " , 0.15]
4 >>> animaux
5 [ ' girafe ' , ' tigre ' , ' singe ' , ' souris ']
6 >>> tailles
7 [5 , 2.5 , 1.75 , 0.15]
8 >>> mixte
9 [ ' girafe ' , 5 , ' souris ' , 0.15]
Lorsque l’on affiche une liste, Python la restitue telle qu’elle a été saisie.
4.2 Utilisation
Un des gros avantages d’une liste est que vous pouvez appeler ses éléments par leur position. Ce numéro est appelé indice
(ou index) de la liste.
1 liste : [" girafe " , " tigre " , " singe " , " souris "]
2 indice : 0 1 2 3
Soyez très attentif au fait que les indices d’une liste de n éléments commencent à 0 et se terminent à n-1. Voyez l’exemple
suivant :
1 >>> animaux = [" girafe " , " tigre " , " singe " , " souris "]
2 >>> animaux [0]
3 ' girafe '
4 >>> animaux [1]
5 ' tigre '
6 >>> animaux [3]
7 ' souris '
Par conséquent, si on appelle l’élément d’indice 4 de notre liste, Python renverra un message d’erreur :
1 >>> animaux [4]
2 Traceback ( innermost last ):
3 File " < stdin >" , line 1 , in ?
4 IndexError : list index out of range
1 >>> ani1 = [" girafe " , " tigre "] 1 >>> animaux = [" girafe " , " tigre " , " singe " , " souris "]
2 >>> ani2 = [" singe " , " souris "] 2 >>> animaux [0:2]
3 >>> ani1 + ani2 3 [ ' girafe ' , ' tigre ']
4 [ ' girafe ' , ' tigre ' , ' singe ' , ' souris '] 4 >>> animaux [0:3]
5 >>> ani1 * 3 5 [ ' girafe ' , ' tigre ' , ' singe ']
6 [ ' girafe ' , ' tigre ' , ' girafe ' , ' tigre ' , ' girafe ' , ' tigre '] 6 >>> animaux [0:]
7 [ ' girafe ' , ' tigre ' , ' singe ' , ' souris ']
L’opérateur + est très pratique pour concaténer deux listes. 8 >>> animaux [:]
Vous pouvez aussi utiliser la méthode .append() lorsque vous souhaitez ajouter un seul élément à la fin d’une liste. 9 [ ' girafe ' , ' tigre ' , ' singe ' , ' souris ']
10 >>> animaux [1:]
Dans l’exemple suivant nous allons créer une liste vide : 11 [ ' tigre ' , ' singe ' , ' souris ']
1 >>> a = [] 12 >>> animaux [1: -1]
2 >>> a 13 [ ' tigre ' , ' singe ']
3 []
Notez que lorsqu’aucun indice n’est indiqué à gauche ou à droite du symbole deux-points, Python prend par défaut tous
puis lui ajouter deux éléments, l’un après l’autre, d’abord avec la concaténation :
les éléments depuis le début ou tous les éléments jusqu’à la fin respectivement.
1 >>> a = a + [15]
2 >>> a On peut aussi préciser le pas en ajoutant un symbole deux-points supplémentaire et en indiquant le pas par un entier.
3 [15] 1 >>> animaux = [" girafe " , " tigre " , " singe " , " souris "]
4 >>> a = a + [ -5] >>> animaux [0:3:2]
5 >>> a 2
Les indices négatifs reviennent à compter à partir de la fin. Leur principal avantage est que vous pouvez accéder au dernier
élément d’une liste à l’aide de l’indice -1 sans pour autant connaître la longueur de cette liste. L’avant-dernier élément a lui 4.7 Les fonctions range() et list()
l’indice -2, l’avant-avant dernier l’indice -3, etc.
1 >>> animaux = [" girafe " , " tigre " , " singe " , " souris "] L’instruction range() est une fonction spéciale en Python qui génère des nombres entiers compris dans un intervalle.
2 >>> animaux [ -1] Lorsqu’elle est utilisée en combinaison avec la fonction list(), on obtient une liste d’entiers. Par exemple :
3 ' souris '
4 >>> animaux [ -2] 1 >>> list ( range (10))
5 ' singe ' 2 [0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9]
Pour accéder au premier élément de la liste avec un indice négatif, il faut par contre connaître le bon indice :
La commande list(range(10)) a généré une liste contenant tous les nombres entiers de 0 inclus à 10 exclu. Nous
1 >>> animaux [ -4] verrons l’utilisation de la fonction range() toute seule dans le chapitre 5 Boucles et comparaisons.
2 ' girafe '
Dans l’exemple ci-dessus, la fonction range() a pris un argument, mais elle peut également prendre deux ou trois argu-
Dans ce cas, on utilise plutôt animaux[0]. ments, voyez plutôt :
1 >>> list ( range (0 , 5))
[0 , 1 , 2 , 3 , 4]
4.5 Tranches 2
3 >>> list ( range (15 , 20))
4 [15 , 16 , 17 , 18 , 19]
Un autre avantage des listes est la possibilité de sélectionner une partie d’une liste en utilisant un indiçage construit sur le 5 >>> list ( range (0 , 1000 , 200))
[0 , 200 , 400 , 600 , 800]
modèle [m:n+1] pour récupérer tous les éléments, du émième au énième (de l’élément m inclus à l’élément n+1 exclu). On
6
7 >>> list ( range (2 , -2 , -1))
dit alors qu’on récupère une tranche de la liste, par exemple : 8 [2 , 1 , 0 , -1]
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 29 30 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
4.8. Listes de listes Chapitre 4. Listes Chapitre 4. Listes 4.10. Exercices
L’instruction range() fonctionne sur le modèle range([début,] fin[, pas]). Les arguments entre crochets sont 1 >>> min ( liste , 3 , 4)
optionnels. Pour obtenir une liste de nombres entiers, il faut l’utiliser systématiquement avec la fonction list(). 2 Traceback ( most recent call last ):
3 File " < stdin >" , line 1 , in < module >
Enfin, prenez garde aux arguments optionnels par défaut (0 pour début et 1 pour pas) : 4 TypeError : '<' not supported between instances of 'int ' and ' list '
1 >>> list ( range (10 ,0)) Soit on passe plusieurs entiers et / ou floats en argument, soit on passe une liste unique.
2 []
Ici la liste est vide car Python a pris la valeur du pas par défaut qui est de 1. Ainsi, si on commence à 10 et qu’on avance par
pas de 1, on ne pourra jamais atteindre 0. Python génère ainsi une liste vide. Pour éviter ça, il faudrait, par exemple, préciser 4.10 Exercices
un pas de -1 pour obtenir une liste d’entiers décroissants :
Conseil : utilisez l’interpréteur Python.
1 >>> list ( range (10 ,0 , -1))
2 [10 , 9 , 8 , 7 , 6 , 5 , 4 , 3 , 2 , 1]
4.10.1 Jours de la semaine
Constituez une liste semaine contenant les 7 jours de la semaine.
4.8 Listes de listes 1. À partir de cette liste, comment récupérez-vous seulement les 5 premiers jours de la semaine d’une part, et ceux du
week-end d’autre part ? Utilisez pour cela l’indiçage.
Pour finir, sachez qu’il est tout à fait possible de construire des listes de listes. Cette fonctionnalité peut parfois être très
pratique. Par exemple : 2. Cherchez un autre moyen pour arriver au même résultat (en utilisant un autre indiçage).
1 >>> enclos1 = [" girafe " , 4] 3. Trouvez deux manières pour accéder au dernier jour de la semaine.
2 >>> enclos2 = [" tigre " , 2]
3 >>> enclos3 = [" singe " , 5]
4. Inversez les jours de la semaine en une commande.
4 >>> zoo = [ enclos1 , enclos2 , enclos3 ]
5 >>> zoo
6 [[ ' girafe ' , 4] , [ ' tigre ' , 2] , [ ' singe ' , 5]] 4.10.2 Saisons
Dans cet exemple, chaque sous-liste contient une catégorie d’animal et le nombre d’animaux pour chaque catégorie. Créez 4 listes hiver, printemps, ete et automne contenant les mois correspondants à ces saisons. Créez ensuite une
Pour accéder à un élément de la liste, on utilise l’indiçage habituel : liste saisons contenant les listes hiver, printemps, ete et automne. Prévoyez ce que renvoient les instructions suivantes,
1 >>> zoo [1]
puis vérifiez-le dans l’interpréteur :
2 [ ' tigre ' , 2] 1. saisons[2]
Pour accéder à un élément de la sous-liste, on utilise un double indiçage : 2. saisons[1][0]
1 >>> zoo [1][0] 3. saisons[1:2]
2 ' tigre '
3 >>> zoo [1][1] 4. saisons[:][1]. Comment expliquez-vous ce dernier résultat ?
4 2
On verra un peu plus loin qu’il existe en Python des dictionnaires qui sont également très pratiques pour stocker de 4.10.3 Table de multiplication par 9
l’information structurée. On verra aussi qu’il existe un module nommé NumPy qui permet de créer des listes ou des tableaux
de nombres (vecteurs et matrices) et de les manipuler. Affichez la table de multiplication par 9 en une seule commande avec les instructions range() et list().
Même si en théorie ces fonctions peuvent prendre en argument une liste de strings, on les utilisera la plupart du temps
avec des types numériques (liste d’entiers et / ou de floats).
Nous avions déjà croisé min(), max() dans le chapitre 2 Variables. On avait vu que ces deux fonctions pouvaient prendre
plusieurs arguments entiers et / ou floats, par exemple :
1 >>> min (3 , 4)
2 3
Attention toutefois à ne pas mélanger entiers et floats d’une part avec une liste d’autre part, car cela renvoie une erreur :
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 31 32 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
Chapitre 5. Boucles et comparaisons 5.1. Boucles for
Les notions de bloc d’instruction et d’indentations ont été introduites dans le chapitre 1 Introduction.
Dans l’exemple suivant, le corps de la boucle contient deux instructions (ligne 2 et ligne 3) car elles sont indentées par
rapport à la ligne débutant par for :
1 for animal in animaux :
print ( animal )
Chapitre 5
2
3 print ( animal *2)
4 print (" C ' est fini ")
La ligne 4 ne fait pas partie du corps de la boucle car elle est au même niveau que le for (c’est-à-dire non indentée par
rapport au for). Notez également que chaque instruction du corps de la boucle doit être indentée de la même manière (ici 4
Boucles et comparaisons espaces).
Remarque
Outre une meilleure lisibilité, les deux-points et l’indentation sont formellement requis en Python. Même si on peut in-
denter comme on veut (plusieurs espaces ou plusieurs tabulations, mais pas une combinaison des deux), les développeurs
5.1 Boucles for recommandent l’utilisation de quatre espaces. Vous pouvez consulter à ce sujet le chapitre 15 Bonnes pratiques de program-
mation en Python.
5.1.1 Principe Faites en sorte de configurer votre éditeur de texte favori de façon à écrire quatre espaces lorsque vous tapez sur la touche
Tab (tabulation).
En programmation, on est souvent amené à répéter plusieurs fois une instruction. Incontournables à tout langage de pro-
grammation, les boucles vont nous aider à réaliser cette tâche répétitive de manière compacte et efficace.
Imaginez par exemple que vous souhaitiez afficher les éléments d’une liste les uns après les autres. Dans l’état actuel de Si on oublie l’indentation, Python renvoie un message d’erreur :
vos connaissances, il faudrait taper quelque chose du style : 1 >>> for animal in animaux :
2 ... print ( animal )
1 animaux = [" girafe " , " tigre " , " singe " , " souris "] 3 File " < stdin >" , line 2
2 print ( animaux [0]) 4 print ( animal )
3 print ( animaux [1]) 5 ^
4 print ( animaux [2]) 6 IndentationEr r o r : expected an indented block
5 print ( animaux [3])
Dans les exemples ci-dessus, nous avons exécuté une boucle en itérant directement sur une liste. Une tranche d’une liste
Si votre liste ne contient que 4 éléments, ceci est encore faisable mais imaginez qu’elle en contienne 100 voire 1000 ! Pour étant elle même une liste, on peut également itérer dessus :
remédier à cela, il faut utiliser les boucles. Regardez l’exemple suivant : 1 >>> animaux = [" girafe " , " tigre " , " singe " , " souris "]
2 >>> for animal in animaux [1:3]:
1 >>> animaux = [" girafe " , " tigre " , " singe " , " souris "] 3 ... print ( animal )
2 >>> for animal in animaux : 4 ...
3 ... print ( animal ) 5 tigre
4 ... 6 singe
5 girafe
6 tigre On a vu que les boucles for pouvaient utiliser une liste contenant des chaînes de caractères, mais elles peuvent tout aussi
7 singe
8 souris bien utiliser des listes contenant des entiers (ou n’importe quel type de variable).
1 >>> for i in [1 , 2 , 3]:
Commentons en détails ce qu’il s’est passé dans cet exemple : 2 ... print ( i )
...
La variable animal est appelée variable d’itération, elle prend successivement les différentes valeurs de la liste animaux 3
4 1
à chaque itération de la boucle. On verra un peu plus loin dans ce chapitre que l’on peut choisir le nom que l’on veut pour 5 2
3
cette variable. Celle-ci est créée par Python la première fois que la ligne contenant le for est exécutée (si elle existait déjà son
6
contenu serait écrasé). Une fois la boucle terminée, cette variable d’itération animal n’est pas détruite et conserve la dernière
valeur de la liste animaux (ici la chaîne de caractères "souris"). 5.1.2 Fonction range()
Notez bien les types des variables utilisées ici :
— animaux est une liste sur laquelle on itère, Python possède la fonction range() que nous avons rencontrée précédemment dans le chapitre 4 sur les Listes et qui est
— animal est une chaîne de caractères car chaque élément de la liste animaux est une chaîne de caractères. aussi bien commode pour faire une boucle sur une liste d’entiers de manière automatique :
Nous verrons plus loin que la variable d’itération peut être de n’importe quel type selon la liste parcourue. En Python, une 1 >>> for i in range (4):
2 ... print ( i )
boucle itère toujours sur un objet dit séquentiel (c’est-à-dire un objet constitué d’autres objets) tel qu’une liste. Nous verrons 3 ...
aussi plus tard d’autres objets séquentiels sur lesquels on peut itérer dans une boucle. 4 0
5 1
D’ores et déjà, prêtez attention au caractère deux-points « : » à la fin de la ligne débutant par for. Cela signifie que la 6 2
3
boucle for attend un bloc d’instructions, en l’occurrence toutes les instructions que Python répétera à chaque itération de la
7
boucle. On appelle ce bloc d’instructions le corps de la boucle. Comment indique-t-on à Python où ce bloc commence et se Dans cet exemple, nous pouvons faire plusieurs remarques importantes :
termine ? Cela est signalé uniquement par l’indentation, c’est-à-dire le décalage vers la droite de la (ou des) ligne(s) du bloc Contrairement à la création de liste avec list(range(4)), la fonction range() peut être utilisée telle quelle dans une
d’instructions. boucle. Il n’est pas nécessaire de taper for i in list(range(4)): même si cela fonctionnerait également.
Comment cela est-ce possible ? Et bien range() est une fonction qui a été spécialement conçue pour cela 1 , c’est-à-
Remarque 1. https://docs.python.org/fr/3/library/stdtypes.html#typesseq-range
dire que l’on peut itérer directement dessus. Pour Python, il s’agit d’un nouveau type, par exemple dans l’instruction x = 5 L ' animal 0 est un ( e ) girafe
range(3) la variable x est de type range (tout comme on avait les types int, float, str ou list) à utiliser spécialement avec les 6 L ' animal 1 est un ( e ) tigre
7 L ' animal 2 est un ( e ) singe
boucles. 8 L ' animal 3 est un ( e ) souris
L’instruction list(range(4)) se contente de transformer un objet de type range en un objet de type list. Si vous vous
souvenez bien, il s’agit d’une fonction de casting, qui convertit un type en un autre (voir chapitre 2 Variables). Il n’y au-
cun intérêt à utiliser dans une boucle la construction for i in list(range(4)):. C’est même contre-productif. En effet,
range() se contente de stocker l’entier actuel, le pas pour passer à l’entier suivant, et le dernier entier à parcourir, ce qui re-
5.2 Comparaisons
vient à stocker seulement 3 nombres entiers et ce quelle que soit la longueur de la séquence, même avec un range(1000000). Avant de passer à une autre sorte de boucles (les boucles while), nous abordons tout de suite les comparaisons. Celles-ci
Si on utilisait list(range(1000000)), Python construirait d’abord une liste de 1 million d’éléments dans la mémoire puis seront reprises dans le chapitre 6 sur les Tests.
itérerait dessus, d’où une énorme perte de temps ! Python est capable d’effectuer toute une série de comparaisons entre le contenu de deux variables, telles que :
>>> animaux = [" girafe " , " tigre " , " singe " , " souris "]
1
2 >>> for i in range (4):
Python renvoie la valeur True si la comparaison est vraie et False si elle est fausse. True et False sont des booléens (un
3 ... print ( animaux [ i ]) nouveau type de variable).
4 ... Faites bien attention à ne pas confondre l’opérateur d’affectation = qui affecte une valeur à une variable et l’opérateur
5 girafe
6 tigre de comparaison == qui compare les valeurs de deux variables.
7 singe
8 souris Vous pouvez également effectuer des comparaisons sur des chaînes de caractères.
>>> animal = " tigre "
La variable i prendra les valeurs successives 0, 1, 2 et 3 et on accèdera à chaque élément de la liste animaux par son 1
2 >>> animal == " tig "
indice (i.e. animaux[i]). Notez à nouveau le nom i de la variable d’itération car on itère sur les indices. 3 False
4 >>> animal != " tig "
Quand utiliser l’une ou l’autre des 2 méthodes ? La plus efficace est celle qui réalise les itérations directement sur les 5 True
éléments : 6 >>> animal == " tigre "
7 True
1 >>> animaux = [" girafe " , " tigre " , " singe " , " souris "]
2 >>> for animal in animaux : Dans le cas des chaînes de caractères, a priori seuls les tests == et != ont un sens. En fait, on peut aussi utiliser les
3 ... print ( animal )
4 ... opérateurs <, >, <= et >=. Dans ce cas, l’ordre alphabétique est pris en compte, par exemple :
5 girafe
6 tigre 1 >>> " a " < " b "
7 singe 2 True
8 souris
"a" est inférieur à "b" car le caractère a est situé avant le caractère b dans l’ordre alphabétique. En fait, c’est l’ordre
Toutefois, il se peut qu’au cours d’une boucle vous ayez besoin des indices, auquel cas vous devrez itérer sur les indices :
ASCII 2 des caractères qui est pris en compte (à chaque caractère correspond un code numérique), on peut donc aussi comparer
1 >>> animaux = [" girafe " , " tigre " , " singe " , " souris "] des caractères spéciaux (comme # ou ~) entre eux. Enfin, on peut comparer des chaînes de caractères de plusieurs caractères :
2 >>> for i in range ( len ( animaux )):
3 ... print ( f "L ' animal { i } est un ( e ) { animaux [ i ]}") 1 >>> " ali " < " alo "
4 ... 2 True
5 L ' animal 0 est un ( e ) girafe 3 >>> " abb " < " ada "
6 L ' animal 1 est un ( e ) tigre 4 True
7 L ' animal 2 est un ( e ) singe
8 L ' animal 3 est un ( e ) souris Dans ce cas, Python compare les deux chaînes de caractères, caractère par caractère, de la gauche vers la droite (le premier
caractère avec le premier, le deuxième avec le deuxième, etc). Dès qu’un caractère est différent entre l’une et l’autre des deux
Python possède toutefois la fonction enumerate() qui vous permet d’itérer sur les indices et les éléments eux-mêmes.
chaînes, il considère que la chaîne la plus petite est celle qui présente le caractère ayant le plus petit code ASCII (les caractères
>>> animaux = [" girafe " , " tigre " , " singe " , " souris "]
1
2 >>> for i , animal in enumerate ( animaux ):
suivants de la chaîne de caractères sont ignorés dans la comparaison), comme dans l’exemple "abb" < "ada" ci-dessus.
3 ... print ( f "L ' animal { i } est un ( e ) { animal }")
4 ... 2. http://fr.wikipedia.org/wiki/American_Standard_Code_for_Information_Interchange
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 35 36 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
5.3. Boucles while Chapitre 5. Boucles et comparaisons Chapitre 5. Boucles et comparaisons 5.4. Exercices
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 37 38 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
5.4. Exercices Chapitre 5. Boucles et comparaisons Chapitre 5. Boucles et comparaisons 5.4. Exercices
F IGURE 5.1 – Parcours d’une matrice. F IGURE 5.2 – Demi-matrice sans la diagonale (en gris).
5.4.10 Pyramide
Créez un script pyra.py qui dessine une pyramide comme celle-ci :
1 *
2 ***
3 *****
4 *******
5 *********
6 ***********
7 *************
8 ************** *
9 ** *** **** *** ** * * * F IGURE 5.3 – Sauts de puce.
10 * * * * ** * * * * * * * * ** * * *
Essayez de faire évoluer votre script pour dessiner la pyramide à partir d’un nombre arbitraire de lignes N. Vous pourrez 1 ligne colonne
demander à l’utilisateur le nombre de lignes de la pyramide avec les instructions suivantes qui utilisent la fonction input() : 2 1 2
3 1 3
1 reponse = input (" Entrez un nombre de lignes ( entier positif ): ") 4 1 4
2 N = int ( reponse ) 5 2 3
6 2 4
7 3 4
8 Pour une matrice 4 x4 , on a parcouru 6 cases
5.4.11 Parcours de matrice Testez votre script avec N=3, puis N=4 et enfin N=5.
Imaginons que l’on souhaite parcourir tous les éléments d’une matrice carrée, c’est-à-dire d’une matrice qui est constituée Concevez une seconde version à partir du script précédent, où cette fois on n’affiche plus tous les couples possibles mais
d’autant de lignes que de colonnes. simplement la valeur de N, et le nombre de cases parcourues. Affichez cela pour des valeurs de N allant de 2 à 10.
Créez un script qui parcourt chaque élément de la matrice et qui affiche le numéro de ligne et de colonne uniquement avec Pouvez-vous trouver une formule générale reliant le nombre de cases parcourues à N ?
des boucles for.
Pour une matrice de dimensions 2 × 2, le schéma de la figure 5.1 vous indique comment parcourir une telle matrice. 5.4.13 Sauts de puce
L’affichage attendu est :
1 ligne colonne
On imagine une puce qui se déplace aléatoirement sur une ligne, en avant ou en arrière, par pas de 1 ou -1. Par exemple,
2 1 1 si elle est à l’emplacement 0, elle peut sauter à l’emplacement 1 ou -1 ; si elle est à l’emplacement 2, elle peut sauter à
3 1 2
4 2 1 l’emplacement 3 ou 1, etc.
5 2 2 Avec une boucle while, simuler le mouvement de cette puce de l’emplacement initial 0 à l’emplacement final 5 (voir le
schéma de la figure 5.3). Combien de sauts sont nécessaires pour réaliser ce parcours ? Relancez plusieurs fois le programme.
Attention à bien respecter l’alignement des chiffres qui doit être justifié à droite sur 4 caractères. Testez avec une matrice
Trouvez-vous le même nombre de sauts à chaque exécution ?
de dimensions 3 × 3, puis 5 × 5, et enfin 10 × 10.
Conseil : vous utiliserez l’instruction random.choice([-1,1]) qui renvoie au hasard les valeurs -1 ou 1 avec la même
Créez une seconde version de votre script, cette fois-ci avec deux boucles while.
probabilité. Avant d’utiliser cette instruction vous mettrez au tout début de votre script la ligne
import random
5.4.12 Parcours de demi-matrice sans la diagonale (exercice ++) Nous reverrons la signification de cette syntaxe particulière dans le chapitre 8 Modules.
En se basant sur le script précédent, on souhaite réaliser le parcours d’une demi-matrice carrée sans la diagonale. On peut
noter que cela produit tous les couples possibles une seule fois (1 et 2 est équivalent à 2 et 1), en excluant par ailleurs chaque 5.4.14 Suite de Fibonacci (exercice +++)
élément avec lui même (1 et 1, 2 et 2, etc). Pour mieux comprendre ce qui est demandé, la figure 5.2 indique les cases à
La suite de Fibonacci 3 est une suite mathématique qui porte le nom de Leonardo Fibonacci, un mathématicien italien
parcourir en gris :
du XIIIe siècle. Initialement, cette suite a été conçue pour décrire la croissance d’une population de lapins, mais elle peut
Créez un script qui affiche le numéro de ligne et de colonne, puis la taille de la matrice N × N et le nombre total de cases
parcourues. Par exemple pour une matrice 4 × 4 (N=4) : 3. https://fr.wikipedia.org/wiki/Suite_de_Fibonacci
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 39 40 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
5.4. Exercices Chapitre 5. Boucles et comparaisons
également être utilisée pour décrire certains motifs géométriques retrouvés dans la nature (coquillages, fleurs de tournesol. . . ).
Pour la suite de Fibonacci (xn ), le terme au rang n (avec n > 1) est la somme des nombres aux rangs n − 1 et n − 2 :
xn = xn−1 + xn−2
Par définition, les deux premiers termes sont x0 = 0 et x1 = 1.
À titre d’exemple, les 10 premiers termes de la suite de Fibonacci sont donc 0, 1, 1, 2, 3, 5, 8, 13, 21 et 34.
Créez un script qui construit une liste fibo avec les 15 premiers termes de la suite de Fibonacci puis l’affiche.
Améliorez ce script en affichant, pour chaque élément de la liste fibo avec n > 1, le rapport entre l’élément de rang n et
l’élément de rang n − 1. Ce rapport tend-il vers une constante ? Si oui, laquelle ?
Chapitre 6
Tests
6.1 Définition
Les tests sont un élément essentiel à tout langage informatique si on veut lui donner un peu de complexité car ils permettent
à l’ordinateur de prendre des décisions. Pour cela, Python utilise l’instruction if ainsi qu’une comparaison que nous avons
abordée au chapitre précédent. Voici un premier exemple :
1 >>> x = 2
2 >>> if x == 2:
3 ... print (" Le test est vrai !")
4 ...
5 Le test est vrai !
et un second :
1 >>> x = " souris "
2 >>> if x == " tigre ":
3 ... print (" Le test est vrai !")
4 ...
On peut utiliser une série de tests dans la même instruction if, notamment pour tester plusieurs valeurs d’une même
variable.
Par exemple, on se propose de tirer au sort une base d’ADN puis d’afficher le nom de cette dernière. Dans le code suivant, et de l’opérateur ET :
nous utilisons l’instruction random.choice(liste) qui renvoie un élément choisi au hasard dans une liste. L’instruction
import random sera vue plus tard dans le chapitre 8 Modules, admettez pour le moment qu’elle est nécessaire. Condition 1 Opérateur Condition 2 Résultat
1 >>> import random
2 >>> base = random . choice ([" a " , " t " , " c " , " g "]) Vrai ET Vrai Vrai
3 >>> if base == " a ": Vrai ET Faux Faux
4 ... print (" choix d ' une ad é nine ")
5 ... elif base == " t ": Faux ET Vrai Faux
6 ... print (" choix d ' une thymine ") Faux ET Faux Faux
7 ... elif base == " c ":
8 ... print (" choix d ' une cytosine ")
9 ... elif base == " g ":
10 ... print (" choix d ' une guanine ") En Python, on utilise le mot réservé and pour l’opérateur ET et le mot réservé or pour l’opérateur OU. Respectez bien la
11 ...
12 choix d ' une cytosine casse des opérateurs and et or qui, en Python, s’écrivent en minuscule. En voici un exemple d’utilisation :
Dans cet exemple, Python teste la première condition, puis, si et seulement si elle est fausse, teste la deuxième et ainsi de 1 >>> x = 2
>>> y = 2
suite. . . Le code correspondant à la première condition vérifiée est exécuté puis Python sort du bloc d’instructions du if.
2
3 >>> if x == 2 and y == 2:
4 ... print (" le test est vrai ")
5 ...
6 le test est vrai
6.3 Importance de l’indentation
Notez que le même résultat serait obtenu en utilisant deux instructions if imbriquées :
De nouveau, faites bien attention à l’indentation ! Vous devez être très rigoureux sur ce point. Pour vous en convaincre,
1 >>> x = 2
exécutez ces deux exemples de code : 2 >>> y = 2
Code 1 3 >>> if x == 2:
4 ... if y == 2:
1 nombres = [4 , 5 , 6] 5 ... print (" le test est vrai ")
2 for nb in nombres : 6 ...
3 if nb == 5: 7 le test est vrai
4 print (" Le test est vrai ")
print ( f " car la variable nb vaut { nb }")
5
Vous pouvez aussi tester directement l’effet de ces opérateurs à l’aide de True et False (attention à respecter la casse).
Résultat : 1 >>> True or False
1 Le test est vrai 2 True
2 car la variable nb vaut 5
Enfin, on peut utiliser l’opérateur logique de négation not qui inverse le résultat d’une condition :
Code 2
1 >>> not True
1 nombres = [4 , 5 , 6] 2 False
2 for nb in nombres : 3 >>> not False
3 if nb == 5: 4 True
4 print (" Le test est vrai ") 5 >>> not ( True and True )
5 print ( f " car la variable nb vaut { nb }") 6 False
Résultat :
1 car la variable nb vaut 4
2 Le test est vrai
3 car la variable nb vaut 5 6.5 Instructions break et continue
4 car la variable nb vaut 6
Les deux codes pourtant très similaires produisent des résultats très différents. Si vous observez avec attention l’indentation Ces deux instructions permettent de modifier le comportement d’une boucle (for ou while) avec un test.
des instructions sur la ligne 5, vous remarquerez que dans le code 1, l’instruction est indentée deux fois, ce qui signifie qu’elle L’instruction break stoppe la boucle.
appartient au bloc d’instructions du test if. Dans le code 2, l’instruction de la ligne 5 n’est indentée qu’une seule fois, ce
qui fait qu’elle n’appartient plus au bloc d’instructions du test if, d’où l’affichage de car la variable nb vaut xx pour 1 >>> for i in range (5):
2 ... if i > 2:
toutes les valeurs de nb. 3 ... break
4 ... print ( i )
5 ...
6 0
6.4 Tests multiples 7
8
1
2
Les tests multiples permettent de tester plusieurs conditions en même temps en utilisant des opérateurs booléens. Les deux L’instruction continue saute à l’itération suivante, sans exécuter la suite du bloc d’instructions de la boucle.
opérateurs les plus couramment utilisés sont le OU et le ET. Voici un petit rappel sur le fonctionnement de l’opérateur OU :
1 >>> for i in range (5):
2 ... if i == 2:
Condition 1 Opérateur Condition 2 Résultat 3 ... continue
4 ... print ( i )
Vrai OU Vrai Vrai 5 ...
6 0
Vrai OU Faux Vrai 7 1
Faux OU Vrai Vrai 8 3
9 4
Faux OU Faux Faux
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 43 44 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
6.6. Tests de valeur sur des floats Chapitre 6. Tests Chapitre 6. Tests 6.7. Exercices
6.6 Tests de valeur sur des floats 6.7.2 Séquence complémentaire d’un brin d’ADN
Lorsque l’on souhaite tester la valeur d’une variable de type float, le premier réflexe serait d’utiliser l’opérateur d’égalité La liste ci-dessous représente la séquence d’un brin d’ADN :
comme : ["A", "C", "G", "T", "T", "A", "G", "C", "T", "A", "A", "C", "G"]
Créez un script qui transforme cette séquence en sa séquence complémentaire.
1 >>> 1/10 == 0.1
2 True Rappel : la séquence complémentaire s’obtient en remplaçant A par T, T par A, C par G et G par C.
Toutefois, nous vous le déconseillons formellement. Pourquoi ? Python stocke les valeurs numériques des floats sous forme
de nombres flottants (d’où leur nom !), et cela mène à certaines limitations 1 . Observez l’exemple suivant : 6.7.3 Minimum d’une liste
1 >>> (3 - 2.7) == 0.3 La fonction min() de Python renvoie l’élément le plus petit d’une liste constituée de valeurs numériques ou de chaînes de
2 False
3 >>> 3 - 2.7 caractères. Sans utiliser cette fonction, créez un script qui détermine le plus petit élément de la liste [8, 4, 6, 1, 5].
4 0 . 29 9 9 9 9 9 99 9 9 9 9 99 8
Nous voyons que le résultat de l’opération 3 - 2.7 n’est pas exactement 0.3 d’où le False en ligne 2. 6.7.4 Fréquence des acides aminés
En fait, ce problème ne vient pas de Python, mais plutôt de la manière dont un ordinateur traite les nombres flottants
(comme un rapport de nombres binaires). Ainsi certaines valeurs de float ne peuvent être qu’approchées. Une manière de s’en La liste ci-dessous représente une séquence d’acides aminés :
rendre compte est d’utiliser l’écriture formatée en demandant l’affichage d’un grand nombre de décimales : ["A", "R", "A", "W", "W", "A", "W", "A", "R", "W", "W", "R", "A", "G"]
1 >>> 0.3 Calculez la fréquence des acides aminés alanine (A), arginine (R), tryptophane (W) et glycine (G) dans cette séquence.
2 0.3
3 >>> f "{0.3:.5 f }"
'0.30000 '
4
5 >>> f "{0.3:.60 f }"
6.7.5 Notes et mention d’un étudiant
6 '0.299999999999999988897769753748434595763683319091796875000000 '
7 >>> f "{3 - 2.7:.60 f }" Voici les notes d’un étudiant : 14, 9, 13, 15 et 12. Créez un script qui affiche la note maximum (utilisez la fonction max()),
8 '0.299999999999999822364316059974953532218933105468750000000000 ' la note minimum (utilisez la fonction min()) et qui calcule la moyenne.
On observe que lorsqu’on tape 0.3, Python affiche une valeur arrondie. En réalité, le nombre réel 0.3 ne peut être Affichez la valeur de la moyenne avec deux décimales. Affichez aussi la mention obtenue sachant que la mention est «
qu’approché lorsqu’on le code en nombre flottant. Il est donc essentiel d’avoir cela en tête lorsque l’on effectue un test. passable » si la moyenne est entre 10 inclus et 12 exclus, « assez bien » entre 12 inclus et 14 exclus et « bien » au-delà de 14.
Vous remarquerez qu’un nombre est pair lorsque le reste de sa division entière par 2 est nul.
6.7 Exercices
Conseil : pour ces exercices, créez des scripts puis exécutez-les dans un shell. 6.7.7 Conjecture de Syracuse (exercice +++)
La conjecture de Syracuse 2 est une conjecture mathématique qui reste improuvée à ce jour et qui est définie de la manière
6.7.1 Jours de la semaine suivante.
Soit un entier positif n. Si n est pair, alors le diviser par 2. Si il est impair, alors le multiplier par 3 et lui ajouter 1. En
Constituez une liste semaine contenant le nom des sept jours de la semaine. répétant cette procédure, la suite de nombres atteint la valeur 1 puis se prolonge indéfiniment par une suite de trois valeurs
En utilisant une boucle, écrivez chaque jour de la semaine ainsi que les messages suivants : triviales appelée cycle trivial.
— Au travail s’il s’agit du lundi au jeudi ; Jusqu’à présent, la conjecture de Syracuse, selon laquelle depuis n’importe quel entier positif la suite de Syracuse atteint
— Chouette c'est vendredi s’il s’agit du vendredi ; 1, n’a pas été mise en défaut.
— Repos ce week-end s’il s’agit du samedi ou du dimanche. Par exemple, les premiers éléments de la suite de Syracuse si on prend comme point de départ 10 sont : 10, 5, 16, 8, 4, 2,
Ces messages ne sont que des suggestions, vous pouvez laisser libre cours à votre imagination. 1. . .
1. https://docs.python.org/fr/3/tutorial/floatingpoint.html 2. http://fr.wikipedia.org/wiki/Conjecture_de_Syracuse
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 45 46 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
6.7. Exercices Chapitre 6. Tests Chapitre 6. Tests 6.7. Exercices
Créez un script qui, partant d’un entier positif n (par exemple 10 ou 20), crée une liste des nombres de la suite de Syracuse. Méthode 1 (peu optimale mais assez intuitive)
Avec différents points de départ (c’est-à-dire avec différentes valeurs de n), la conjecture de Syracuse est-elle toujours vérifiée ?
Pour chaque nombre de 2 à 100, calculez le reste de la division entière (avec l’opérateur modulo %) depuis 1 jusqu’à
Quels sont les nombres qui constituent le cycle trivial ?
lui-même. Si c’est un nombre premier, il aura exactement deux nombres pour lesquels le reste de la division entière est égal à
0 (1 et lui-même). Si ce n’est pas un nombre premier, il aura plus de deux nombres pour lesquels le reste de la division entière
Remarque est égal à 0.
1. Pour cet exercice, vous avez besoin de faire un nombre d’itérations inconnu pour que la suite de Syracuse atteigne
le chiffre 1 puis entame son cycle trivial. Vous pourrez tester votre algorithme avec un nombre arbitraire d’itérations, Méthode 2 (plus optimale et plus rapide, mais un peu plus compliquée)
typiquement 20 ou 100, suivant votre nombre n de départ.
Parcourez tous les nombres de 2 à 100 et vérifiez si ceux-ci sont composés, c’est-à-dire qu’ils sont le produit de deux
2. Un nombre est pair lorsque le reste de sa division entière (opérateur modulo %) par 2 est nul. nombres premiers. Pratiquement, cela consiste à vérifier que le reste de la division entière (opérateur modulo %) entre le
nombre considéré et chaque nombre premier déterminé jusqu’à maintenant est nul. Le cas échéant, ce nombre n’est pas
premier. Attention, pour cette méthode, il faudra initialiser la liste de nombres premiers avec le premier nombre premier (donc
2 !).
6.7.8 Attribution de la structure secondaire des acides aminés d’une protéine (exercice +++)
Dans une protéine, les différents acides aminés sont liés entre eux par une liaison peptidique. Les angles phi et psi sont 6.7.10 Recherche d’un nombre par dichotomie (exercice +++)
deux angles mesurés autour de cette liaison peptidique. Leurs valeurs sont utiles pour définir la conformation spatiale (appelée La recherche par dichotomie 6 est une méthode qui consiste à diviser (en général en parties égales) un problème pour en
« structure secondaire ») adoptée par les acides aminés. trouver la solution. À titre d’exemple, voici une discussion entre Pierre et Patrick dans laquelle Pierre essaie de deviner le
Par exemples, les angles phi et psi d’une conformation en « hélice alpha » parfaite ont une valeur de -57 degrés et -47 nombre (compris entre 1 et 100 inclus) auquel Patrick a pensé.
degrés respectivement. Bien sûr, il est très rare que l’on trouve ces valeurs parfaites dans une protéine, et il est habituel de — [Patrick] « C’est bon, j’ai pensé à un nombre entre 1 et 100. »
tolérer une déviation de ± 30 degrés autour des valeurs idéales de ces angles. — [Pierre] « OK, je vais essayer de le deviner. Est-ce que ton nombre est plus petit ou plus grand que 50 ? »
Vous trouverez ci-dessous une liste de listes contenant les valeurs des angles phi et psi de 15 acides aminés de la protéine — [Patrick] « Plus grand. »
1TFE 3 : — [Pierre] « Est-ce que ton nombre est plus petit, plus grand ou égal à 75 ? »
1 [[48.6 , 53.4] ,[ -124.9 , 156.7] ,[ -66.2 , -30.8] , \ — [Patrick] « Plus grand. »
2 [ -58.8 , -43.1] ,[ -73.9 , -40.6] ,[ -53.7 , -37.5] , \
3 [ -80.6 , -26.0] ,[ -68.5 , 135.0] ,[ -64.9 , -23.5] , \
— [Pierre] « Est-ce que ton nombre est plus petit, plus grand ou égal à 87 ? »
4 [ -66.9 , -45.5] ,[ -69.6 , -41.0] ,[ -62.7 , -37.5] , \ — [Patrick] « Plus petit. »
5 [ -68.2 , -38.3] ,[ -61.2 , -49.1] ,[ -59.7 , -41.1]] — [Pierre] « Est-ce que ton nombre est plus petit, plus grand ou égal à 81 ? »
Pour le premier acide aminé, l’angle phi vaut 48.6 et l’angle psi 53.4. Pour le deuxième, l’angle phi vaut -124.9 et l’angle — [Patrick] « Plus petit. »
psi 156.7, etc. — [Pierre] « Est-ce que ton nombre est plus petit, plus grand ou égal à 78 ? »
En utilisant cette liste, créez un script qui teste, pour chaque acide aminé, s’il est ou non en hélice et affiche les valeurs des — [Patrick] « Plus grand. »
angles phi et psi et le message adapté est en hélice ou n’est pas en hélice. — [Pierre] « Est-ce que ton nombre est plus petit, plus grand ou égal à 79 ? »
Par exemple, pour les 3 premiers acides aminés : — [Patrick] « Égal. C’est le nombre auquel j’avais pensé. Bravo ! »
Pour arriver rapidement à deviner le nombre, l’astuce consiste à prendre à chaque fois la moitié de l’intervalle dans lequel
1 [48.6 , 53.4] n ' est pas en h é lice
2 [ -124.9 , 156.7] n ' est pas en h é lice se trouve le nombre. Voici le détail des différentes étapes :
3 [ -66.2 , -30.8] est en h é lice
1. le nombre se trouve entre 1 et 100, on propose 50 (100 / 2).
D’après vous, quelle est la structure secondaire majoritaire de ces 15 acides aminés ? 2. le nombre se trouve entre 50 et 100, on propose 75 ( 50 + (100-50)/2 ).
3. le nombre se trouve entre 75 et 100, on propose 87 ( 75 + (100-75)/2 ).
Remarque
4. le nombre se trouve entre 75 et 87, on propose 81 ( 75 + (87-75)/2 ).
Pour en savoir plus sur le monde merveilleux des protéines, n’hésitez pas à consulter la page Wikipedia sur la structure
secondaire des protéines 4 . 5. le nombre se trouve entre 75 et 81, on propose 78 ( 75 + (81-75)/2 ).
6. le nombre se trouve entre 78 et 81, on propose 79 ( 78 + (81-78)/2 ).
Créez un script qui reproduit ce jeu de devinettes. Vous pensez à un nombre entre 1 et 100 et l’ordinateur essaie de le
deviner par dichotomie en vous posant des questions.
6.7.9 Détermination des nombres premiers inférieurs à 100 (exercice +++) Votre programme utilisera la fonction input() pour interagir avec l’utilisateur. Voici un exemple de son fonctionnement :
Voici un extrait de l’article sur les nombres premiers tiré de l’encyclopédie en ligne wikipédia 5 . 1 >>> lettre = input (" Entrez une lettre : ")
Un nombre premier est un entier naturel qui admet exactement deux diviseurs distincts entiers et positifs (qui sont alors 1 2 Entrez une lettre : P
3 >>> print ( lettre )
et lui-même). Cette définition exclut 1, qui n’a qu’un seul diviseur entier positif. Par opposition, un nombre non nul produit 4 P
de deux nombres entiers différents de 1 est dit composé. Par exemple 6 = 2 × 3 est composé, tout comme 21 = 3 × 7, mais 11
Pour vous guider, voici ce que donnerait le programme avec la conversation précédente :
est premier car 1 et 11 sont les seuls diviseurs de 11. Les nombres 0 et 1 ne sont ni premiers ni composés.
Déterminez les nombres premiers inférieurs à 100. Combien y a-t-il de nombres premiers entre 0 et 100 ? Pour vous aider, 1 Pensez à un nombre entre 1 et 100.
2 Est - ce votre nombre est plus grand , plus petit ou é gal à 50 ? [+/ -/=] +
nous vous proposons plusieurs méthodes. 3 Est - ce votre nombre est plus grand , plus petit ou é gal à 75 ? [+/ -/=] +
4 Est - ce votre nombre est plus grand , plus petit ou é gal à 87 ? [+/ -/=] -
3. https://www.rcsb.org/structure/1TFE 5 Est - ce votre nombre est plus grand , plus petit ou é gal à 81 ? [+/ -/=] -
4. https://fr.wikipedia.org/wiki/Structure_des_prot%C3%A9ines#Angles_di%C3%A8dres_et_structure_secondaire
5. http://fr.wikipedia.org/wiki/Nombre_premier 6. https://fr.wikipedia.org/wiki/Dichotomie
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 47 48 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
6.7. Exercices Chapitre 6. Tests
6 Est - ce votre nombre est plus grand , plus petit ou é gal à 78 ? [+/ -/=] +
7 Est - ce votre nombre est plus grand , plus petit ou é gal à 79 ? [+/ -/=] =
8 J ' ai trouv é en 6 questions !
Les caractères [+/-/=] indiquent à l’utilisateur comment il doit interagir avec l’ordinateur, c’est-à-dire entrer soit le
caractère + si le nombre choisi est plus grand que le nombre proposé par l’ordinateur, soit le caractère - si le nombre choisi
est plus petit que le nombre proposé par l’ordinateur, soit le caractère = si le nombre choisi est celui proposé par l’ordinateur
(en appuyant ensuite sur la touche Entrée).
Chapitre 7
Fichiers
1 >>> filin = open (" zoo . txt " , " r ") 4 ' girafe \ ntigre \ nsinge \ nsouris \n '
2 >>> lignes = filin . readlines () 5 >>>
3 >>> lignes
4 [ ' girafe \n ' , ' tigre \n ' , ' singe \n ' , ' souris \n ']
5 >>> for ligne in lignes :
6 ... print ( ligne ) 7.1.3 Méthode .readline()
7 ...
8 girafe La méthode .readline() (sans s à la fin) lit une ligne d’un fichier et la renvoie sous forme de chaîne de caractères. À
9
10 tigre chaque nouvel appel de .readline(), la ligne suivante est renvoyée. Associée à la boucle while, cette méthode permet de
11
12 singe
lire un fichier ligne par ligne.
13 1 >>> with open (" zoo . txt " , " r ") as filin :
14 souris 2 ... ligne = filin . readline ()
15
3 ... while ligne != "":
16 >>> filin . close () 4 ... print ( ligne )
5 ... ligne = filin . readline ()
Vous voyez qu’en cinq lignes de code, vous avez lu, parcouru le fichier et affiché son contenu. 6 ...
7 girafe
8
Remarque 9 tigre
10
— Chaque élément de la liste lignes est une chaîne de caractères. C’est en effet sous forme de chaînes de caractères que 11 singe
12
Python lit le contenu d’un fichier. 13 souris
— Chaque élément de la liste lignes se termine par le caractère \n. Ce caractère un peu particulier correspond au « saut 14
15 >>>
de ligne 1 » qui permet de passer d’une ligne à la suivante. Ceci est codé par un caractère spécial que l’on représente par
\n. Vous pourrez parfois rencontrer également la notation octale \012. Dans la suite de cet ouvrage, nous emploierons
aussi l’expression « retour à la ligne » que nous trouvons plus intuitive. 7.1.4 Itérations directe sur le fichier
— Par défaut, l’instruction print() affiche quelque chose puis revient à la ligne. Ce retour à la ligne dû à print() se
cumule alors avec celui de la fin de ligne (\n) de chaque ligne du fichier et donne l’impression qu’une ligne est sautée Python essaie de vous faciliter la vie au maximum. Voici un moyen à la fois simple et élégant de parcourir un fichier.
à chaque fois. 1 >>> with open (" zoo . txt " , " r ") as filin :
2 ... for ligne in filin :
3 ... print ( ligne )
4 ...
Il existe en Python le mot-clé with qui permet d’ouvrir et de fermer un fichier de manière efficace. Si pour une raison ou 5 girafe
6
une autre l’ouverture ou la lecture du fichier conduit à une erreur, l’utilisation de with garantit la bonne fermeture du fichier, 7 tigre
ce qui n’est pas le cas dans le code précédent. Voici donc le même exemple avec with : 8
9 singe
1 >>> with open (" zoo . txt " , 'r ') as filin : 10
11 souris
2 ... lignes = filin . readlines () 12
3 ... for ligne in lignes : 13 >>>
4 ... print ( ligne )
5 ... L’objet filin est « itérable », ainsi la boucle for va demander à Python d’aller lire le fichier ligne par ligne.
6 girafe
7
8 tigre
9 Conseil
10 singe Privilégiez cette méthode par la suite.
11
12 souris
13
14 >>>
Remarque
Remarque Les méthodes abordées précédemment permettent d’accéder au contenu d’un fichier, soit ligne par ligne (méthode .readline()),
— L’instruction with introduit un bloc d’indentation. C’est à l’intérieur de ce bloc que nous effectuons toutes les opéra- soit globalement en une seule chaîne de caractères (méthode .read()), soit globalement avec les lignes différenciées sous
tions sur le fichier. forme d’une liste de chaînes de caractères (méthode .readlines()). Il est également possible en Python de se rendre à un
— Une fois sorti du bloc d’indentation, Python fermera automatiquement le fichier. Vous n’avez donc plus besoin endroit particulier d’un fichier avec la méthode .seek() mais qui sort du cadre de cet ouvrage.
d’utiliser la méthode .close().
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 51 52 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
7.3. Ouvrir deux fichiers avec l’instruction with Chapitre 7. Fichiers Chapitre 7. Fichiers 7.5. Importance des conversions de types avec les fichiers
Quelques commentaires sur cet exemple : Toutefois, Windows utilise deux caractères spéciaux pour le retour à la ligne : \r correspondant à un retour chariot (hérité
Ligne 1. Création d’une liste de chaînes de caractères animaux2. des machines à écrire) et \n comme sous Unix.
Ligne 2. Ouverture du fichier zoo2.txt en mode écriture, avec le caractère w pour write. L’instruction with crée un bloc Si vous avez commencé à programmer en Python 2, vous aurez peut-être remarqué que selon les versions, la lecture de
d’instructions qui doit être indenté. fichier supprimait parfois les \r et d’autres fois les laissait. Heureusement, la fonction open() dans Python 3 3 gère tout
Ligne 3. Parcours de la liste animaux2 avec une boucle for. ça automatiquement et renvoie uniquement des sauts de ligne sous forme d’un seul \n (même si le fichier a été conçu sous
Ligne 4. À chaque itération de la boucle, nous avons écrit chaque élément de la liste dans le fichier. La méthode .write() Windows et qu’il contient initialement des \r).
s’applique sur l’objet filout. Notez qu’à chaque utilisation de la méthode .write(), celle-ci nous affiche le nombre d’octets
(équivalent au nombre de caractères) écrits dans le fichier (lignes 6 à 8). Ceci est valable uniquement dans l’interpréteur, si
vous créez un programme avec les mêmes lignes de code, ces valeurs ne s’afficheront pas à l’écran. 7.5 Importance des conversions de types avec les fichiers
Si nous ouvrons le fichier zoo2.txt avec un éditeur de texte, voici ce que nous obtenons :
poissonabeillechat Vous avez sans doute remarqué que les méthodes qui lisent un fichier (par exemple .readlines()) vous renvoient sys-
Ce n’est pas exactement le résultat attendu car implicitement nous voulions le nom de chaque animal sur une ligne. Nous tématiquement des chaînes de caractères. De même, pour écrire dans un fichier il faut fournir une chaîne de caractères à la
avons oublié d’ajouter le caractère fin de ligne après chaque nom d’animal. méthode .write().
Pour ce faire, nous pouvons utiliser l’écriture formatée : Pour tenir compte de ces contraintes, il faudra utiliser les fonctions de conversions de types vues au chapitre 2 Variables :
1 >>> animaux2 = [" poisson " , " abeille " , " chat "]
int(), float() et str(). Ces fonctions de conversion sont essentielles lorsqu’on lit ou écrit des nombres dans un fichier.
2 >>> with open (" zoo2 . txt " , " w ") as filout : En effet, les nombres dans un fichier sont considérés comme du texte, donc comme des chaînes de caractères, par la
3 ... for animal in animaux2 : méthode .readlines(). Par conséquent, il faut les convertir (en entier ou en float) si on veut effectuer des opérations
4 ... filout . write ( f "{ animal }\ n ")
5 ... numériques avec.
6 8
7 8
8 5
Ligne 4. L’écriture formatée vue au chapitre 3 Affichage permet d’ajouter un retour à la ligne (\n) après le nom de chaque
7.6 Du respect des formats de données et de fichiers
animal. Maintenant que vous savez lire et écrire des fichiers en Python, vous êtes capables de manipuler beaucoup d’information
Lignes 6 à 8. Le nombre d’octets écrits dans le fichier est augmenté de 1 par rapport à l’exemple précédent car le caractère en biologie. Prenez garde cependant aux formats de fichiers, c’est-à-dire à la manière dont est stockée l’information biologique
retour à la ligne compte pour un seul octet. dans des fichiers. Nous vous renvoyons pour cela à l’annexe A Quelques formats de données rencontrés en biologie.
Le contenu du fichier zoo2.txt est alors :
1 poisson
abeille
2
3 chat 7.7 Exercices
Vous voyez qu’il est extrêmement simple en Python de lire ou d’écrire dans un fichier. Conseil : pour ces exercices, créez des scripts puis exécutez-les dans un shell.
7.3 Ouvrir deux fichiers avec l’instruction with 7.7.1 Moyenne des notes
On peut avec l’instruction with ouvrir deux fichiers (ou plus) en même temps. Voyez l’exemple suivant : Le fichier notes.txt 4 contient les notes obtenues par des étudiants pour le cours de Python. Chaque ligne du fichier ne
contient qu’une note.
1 with open (" zoo . txt " , " r ") as fichier1 , open (" zoo2 . txt " , " w ") as fichier2 :
2 for ligne in fichier1 : Téléchargez le fichier notes.txt et enregistrez-le dans votre répertoire de travail. N’hésitez pas à l’ouvrir avec un éditeur
3 fichier2 . write ("* " + ligne ) de texte pour voir à quoi il ressemble.
Si le fichier zoo.txt contient le texte suivant : Créez un script Python qui lit chaque ligne de ce fichier, extrait les notes sous forme de float et les stocke dans une liste.
1 souris Terminez le script en calculant et affichant la moyenne des notes avec deux décimales.
2 girafe
3 lion
4 singe 7.7.2 Admis ou recalé
alors le contenu de zoo2.txt sera : Le fichier notes.txt 5 contient les notes obtenues par des étudiants pour le cours de Python. Chaque ligne du fichier ne
1 * souris contient qu’une note.
2 * girafe
3 * lion Téléchargez le fichier notes.txt et enregistrez-le dans votre répertoire de travail. N’hésitez pas l’ouvrir avec un éditeur
4 * singe
de texte pour voir à quoi il ressemble.
Dans cet exemple, with permet une notation très compacte en s’affranchissant de deux méthodes .close(). Créez un script Python qui lit chaque ligne de ce fichier, extrait les notes sous forme de float et les stocke dans une liste.
Si vous souhaitez aller plus loin, sachez que l’instruction with est plus générale et est utilisable dans d’autres contextes 2 . Le script réécrira ensuite les notes dans le fichier notes2.txt avec une note par ligne suivie de « recalé » si la note est
inférieure à 10 et « admis » si la note est supérieure ou égale à 10. Toutes les notes seront écrites avec une décimale. À titre
d’exemple, voici les 3 premières lignes attendues pour le fichier notes2.txt :
7.4 Note sur les retours à la ligne sous Unix et sous Windows 1 13.5 admis
2 17.0 admis
Conseil : si vous êtes débutant, vous pouvez sauter cette rubrique. 3 9.5 recal é
On a vu plus haut que le caractère spécial \n correspondait à un retour à la ligne. C’est le standard sous Unix (Mac OS X
et Linux). 3. https://docs.python.org/fr/3/library/functions.html#open
4. https://python.sdv.univ-paris-diderot.fr/data-files/notes.txt
2. https://docs.python.org/fr/3/reference/compound_stmts.html#the-with-statement 5. https://python.sdv.univ-paris-diderot.fr/data-files/notes.txt
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 53 54 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
7.7. Exercices Chapitre 7. Fichiers Chapitre 7. Fichiers 7.7. Exercices
4 0.76427 0.23642
5 0.82895 0.35048
6 0.87758 0.47943
7 [...] [...]
Une fois que vous avez généré le fichier spirale.dat, visualisez votre spirale avec le code suivant (que vous pouvez
recopier dans un autre script ou à la suite de votre script spirale.py) :
1 import matplotlib . pyplot as plt
2
3 x = []
4 y = []
5 with open (" spirale . dat " , " r ") as f_in :
6 for line in f_in :
7 coords = line . split ()
8 x . append ( float ( coords [0]))
9 y . append ( float ( coords [1]))
10
11 plt . figure ( figsize =(8 ,8))
12 mini = min ( x + y ) * 1.2
13 maxi = max ( x + y ) * 1.2
14 plt . xlim ( mini , maxi )
15 plt . ylim ( mini , maxi )
16 plt . plot (x , y )
17 plt . savefig (" spirale . png ")
xA = cos(θ ) × r
yA = sin(θ ) × r
Pour calculer les coordonnées cartésiennes qui décrivent la spirale, vous allez faire varier deux variables en même temps :
— l’angle θ , qui va prendre des valeurs de 0 à 4π radians par pas de 0.1, ce qui correspond à deux tours complets ;
— le rayon du cercle r, qui va prendre comme valeur initiale 0.5 puis que vous allez incrémenter (c’est-à-dire augmenter)
par pas de 0.1.
Les fonctions trigonométriques sinus et cosinus sont disponibles dans le module math que vous découvrirez plus en détails
dans le chapitre 8 Modules. Pour les utiliser, vous ajouterez au début de votre script l’instruction :
import math
La fonction sinus sera math.sin() et la fonction cosinus math.cos(). Ces deux fonctions prennent comme argument
une valeur d’angle en radian. La constante mathématique π sera également accessible grâce à ce module via math.pi. Par
exemple :
1 >>> math . sin (0)
2 0.0
3 >>> math . sin ( math . pi /2)
4 1.0
5 >>> math . cos ( math . pi )
6 -1.0
Sauvegardez ensuite les coordonnées cartésiennes dans le fichier spirale.dat en respectant le format suivant :
— un couple de coordonnées (xA et yA ) par ligne ;
— au moins un espace entre les deux coordonnées xA et yA ;
— les coordonnées affichées sur 10 caractères avec 5 chiffres après la virgule.
Les premières lignes de spirale.dat devrait ressembler à :
1 0.50000 0.00000
2 0.59700 0.05990
3 0.68605 0.13907
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 55 56 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
Chapitre 8. Modules 8.3. Obtenir de l’aide sur les modules importés
Par exemple, la méthode .format() (vue au chapitre 3) dans l’instruction "{}".format(3.14) utilise l’objet chaîne de
caractères "{}" (auquel elle est liée) pour finalement renvoyer une autre chaîne de caractères "3.14".
Avec les modules, nous rencontrons une syntaxe similaire. Par exemple, dans l’instruction math.cos(), on pourrait penser
que .cos() est aussi une méthode. En fait la documentation officielle de Python 3 précise bien que dans ce cas .cos() est
une fonction. Dans cet ouvrage, nous utiliserons ainsi le mot fonction lorsqu’on évoquera des fonctions issues de modules.
Si cela vous parait encore ardu, ne vous inquiétez pas, c’est à force de pratiquer et de lire que vous vous approprierez le
Chapitre 8 vocabulaire. Ici, la syntaxe module.fonction() est là pour rappeler de quel module provient la fonction en un coup d’œil !
Modules 1
2
3
>>> from random import randint
>>> randint (0 ,10)
7
À l’aide du mot-clé from, on peut importer une fonction spécifique d’un module donné. Remarquez bien qu’il est inutile
de répéter le nom du module dans ce cas, seul le nom de la fonction en question est requis.
On peut également importer toutes les fonctions d’un module :
8.1 Définition 1 >>> from random import *
2 >>> randint (0 ,50)
Les modules sont des programmes Python qui contiennent des fonctions que l’on est amené à réutiliser souvent (on les 3 46
appelle aussi bibliothèques ou libraries). Ce sont des « boîtes à outils » qui vont vous être très utiles. 4 >>> uniform (0 ,2.5)
5 0 . 6 4 9 4 3 1 7 4 7 6 07 2 7 9 5 1
Les développeurs de Python ont mis au point de nombreux modules qui effectuent une quantité phénoménale de tâches.
Pour cette raison, prenez toujours le réflexe de vérifier si une partie du code que vous souhaitez écrire n’existe pas déjà sous L’instruction from random import * importe toutes les fonctions du module random. On peut ainsi utiliser toutes ses
forme de module. fonctions directement, comme par exemple randint() et uniform() qui renvoie des nombres aléatoires entiers et floats.
La plupart de ces modules sont déjà installés dans les versions standards de Python. Vous pouvez accéder à une docu- Dans la pratique, plutôt que de charger toutes les fonctions d’un module en une seule fois :
mentation exhaustive 1 sur le site de Python. N’hésitez pas à explorer un peu ce site, la quantité de modules disponibles est 1 from random import *
impressionnante (plus de 300).
nous vous conseillons de charger le module seul de la manière suivante :
1 import random
8.2 Importation de modules puis d’appeler explicitement les fonctions voulues, par exemple :
1 random . randint (0 ,2)
Dans les chapitres précédents, nous avons rencontré la notion de module plusieurs fois. Notamment lorsque nous avons
voulu tirer un nombre aléatoire : Il est également possible de définir un alias (un nom plus court) pour un module :
1 >>> import random 1 >>> import random as rand
2 >>> random . randint (0 , 10) 2 >>> rand . randint (1 , 10)
3 4 3 6
4 >>> rand . uniform (1 , 3)
Regardons de plus près cet exemple : 5 2. 643 47 261 654 4 2 3 6
— Ligne 1, l’instruction import donne accès à toutes les fonctions du module random 2 . Dans cet exemple, les fonctions du module random sont accessibles via l’alias rand.
— Ensuite, ligne 2, nous utilisons la fonction randint(0, 10) du module random. Cette fonction renvoie un nombre Enfin, pour vider de la mémoire un module déjà chargé, on peut utiliser l’instruction del :
entier tiré aléatoirement entre 0 inclus et 10 inclus.
1 >>> import random
Nous avons également croisé le module math lors de l’exercice sur la spirale (voir chapitre 7 Fichiers). Ce module nous a 2 >>> random . randint (0 ,10)
donné accès aux fonctions trigonométriques sinus et cosinus, et à la constante π : 3 2
4 >>> del random
1 >>> import math 5 >>> random . randint (0 ,10)
2 >>> math . cos ( math . pi / 2) 6 Traceback ( most recent call last ):
3 6. 12 323 39 957 36 7 66 e -17 7 File " < stdin >" , line 1 , in ?
4 >>> math . sin ( math . pi / 2) 8 NameError : name ' random ' is not defined
5 1.0
On constate alors qu’un rappel (ligne 5) d’une fonction du module random après l’avoir vidé de la mémoire (ligne 4)
En résumé, l’utilisation de la syntaxe import module permet d’importer tout une série de fonctions organisées par « retourne un message d’erreur (lignes 6-8).
thèmes ». Par exemple, les fonctions gérant les nombres aléatoires avec random et les fonctions mathématiques avec math.
Python possède de nombreux autres modules internes (c’est-à-dire présent de base lorsqu’on installe Python).
8.3 Obtenir de l’aide sur les modules importés
Remarque
Dans le chapitre 3 Affichage, nous avons introduit la syntaxe truc.bidule() avec truc étant un objet et .bidule() une Pour obtenir de l’aide sur un module rien de plus simple, il suffit d’utiliser la commande help() :
méthode. Nous vous avions expliqué qu’une méthode était une fonction un peu particulière : 1 >>> import random
2 >>> help ( random )
— elle était liée à un objet par un point ; 3 [...]
— en général, elle agissait sur ou utilisait l’objet auquel elle était liée.
Ce qui renvoie quelque chose du type :
1. https://docs.python.org/fr/3/py-modindex.html
2. https://docs.python.org/fr/3/library/random.html#module-random 3. https://docs.python.org/fr/3/tutorial/modules.html
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 59 60 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
8.6. Module sys : passage d’arguments Chapitre 8. Modules Chapitre 8. Modules 8.6. Module sys : passage d’arguments
9 [ 'A ' , 'T ' , 'A ' , 'A ' , 'C '] Ligne 1. Le caractère $ représente l’invite du shell, test.py est le nom du script Python, salut, girafe et 42 sont les
10 >>> random . choices ( bases , k =10) arguments passés au script (tous séparés par un espace).
11 [ 'C ' , 'T ' , 'T ' , 'T ' , 'G ' , 'A ' , 'C ' , 'A ' , 'G ' , 'G ']
Ligne 2. Le script affiche le contenu de la variable sys.argv. Cette variable est une liste qui contient tous les arguments
La fonction choice() tire aléatoirement un élément d’une liste alors que choices() (avec un s à la fin) réalise plusieurs de la ligne de commande, y compris le nom du script lui-même qu’on retrouve comme premier élément de cette liste dans
tirages aléatoires, dont le nombre est précisé par le paramètre k. sys.argv[0]. On peut donc accéder à chacun des arguments du script avec sys.argv[1], sys.argv[2]. . .
Si vous exécutez vous-même les exemples précédents, vous devriez obtenir des résultats légèrement différents de ceux Toujours dans le module sys, la fonction sys.exit() est utile pour quitter un script Python. On peut donner un argument
indiqués. C’est l’intérêt de l’aléatoire ! à cette fonction (en général une chaîne de caractères) qui sera renvoyé au moment où Python quittera le script. Par exemple,
Pour des besoins de reproductibilité des analyses en science, on a souvent besoin de retrouver les mêmes résultats même si vous attendez au moins un argument en ligne de commande, vous pouvez renvoyer un message pour indiquer à l’utilisateur
si on utilise des nombres aléatoires. Pour cela, on peut définir ce qu’on appelle la « graine aléatoire ». ce que le script attend comme argument :
1 import sys
2
Définition 3 if len ( sys . argv ) != 2:
En informatique, la généreration de nombres aléatoires est un problème complexe. On utilise plutôt des « générateurs 4 sys . exit (" ERREUR : il faut exactement un argument .")
de nombres pseudo-aléatoires 14 ». Pour cela, une graine aléatoire 15 doit être définie. Cette graine est la plupart du temps 5
6 print ( f " Argument vaut : { sys . argv [1]}")
un nombre entier qu’on passe au générateur, celui-ci va alors produire une série donnée de nombres pseudo-aléatoires qui
dépendent de cette graine. Si on change la graine, la série de nombres change. Puis on l’exécute sans argument :
1 $ python test . py
2 ERREUR : il faut exactement un argument .
En Python, la graine aléatoire se définit avec la fonction seed() :
1 >>> random . seed (42)
et avec un argument :
2 >>> random . randint (0 , 10) 1 $ python test . py 42
3 1 2 Argument vaut : 42
4 >>> random . randint (0 , 10)
5 0
6 >>> random . randint (0 , 10) Notez qu’ici on vérifie que le script possède deux arguments car le nom du script lui-même compte pour un argument (le
7 4 tout premier).
L’intérêt de récupérer des arguments passés dans la ligne de commande à l’appel du script est de pouvoir ensuite les utiliser
Ici la graine aléatoire est fixée à 42. Si on ne précise pas la graine, par défaut Python utilise la date. Plus précisément, il
dans le script.
s’agit du nombre de secondes écoulées depuis une date donnée du passé. Ainsi, à chaque fois qu’on relance Python, la graine
sera différente car ce nombre de secondes sera différent. Voici à titre d’exemple le script compte_lignes.py qui va prendre comme argument le nom d’un fichier puis afficher le
nombre de lignes qu’il contient.
Si vous exécutez ces mêmes lignes de code (depuis l’instruction random.seed(42)), il se peut que vous ayez des résultats
différents selon la version de Python. Néanmoins, vous devriez systématiquement obtenir les mêmes résultats si vous relancez 1 import sys
2
plusieurs fois de suite ces instructions sur une même machine. 3 if len ( sys . argv ) != 2:
4 sys . exit (" ERREUR : il faut exactement un argument .")
5
Remarque 6 nom_fichier = sys . argv [1]
7 taille = 0
Quand on utlise des nombres aléatoires, il est fondamental de connaitre la distribution de probablités utilisée par la fonc- 8 with open ( nom_fichier , " r ") as f_in :
tion. Par exemple, La fonction de base du module random est random.random(), elle renvoie un float aléatoire entre 0 9 taille = len ( f_in . readlines ())
et 1 tiré dans une distribution uniforme. Si on tire beaucoup de nombres, on aura la même probabilité d’obtenir tous les 10
11 print ( f "{ nom_fichier } contient { taille } lignes .")
nombres possibles entre 0 et 1. La fonction random.randint() tire aussi un entier dans une distribution uniforme. La fonc-
tion random.gauss() tire quant à elle un float aléatoire dans une distribution Gaussienne. Supposons que dans le même répertoire, nous ayons le fichier zoo1.txt dont voici le contenu :
1 girafe
2 tigre
3 singe
4 souris
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 61 62 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
8.7. Module os : interaction avec le système d’exploitation Chapitre 8. Modules Chapitre 8. Modules 8.8. Exercices
Enfin, la fonction os.listdir() renvoie le contenu du répertoire depuis lequel est lancé Python : Générez une séquence aléatoire d’ADN de 20 bases de deux manières différentes. Utilisez le module random avec la
1 >>> import os
fonction randint() ou choice().
2 >>> os . listdir () Documentation de la fonction random.randint() :
3 [ '1 BTA . pdb ' , ' demo . py ' , ' tests '] https://docs.python.org/fr/3/library/random.html#random.randint
Le résultat est renvoyé sous forme d’une liste contenant à la fois le nom des fichiers et des répertoires. Documentation de la fonction random.choice() :
Il existe de nombreuse autres fonctions dans le module os, n’hésitez pas à consulter la documentation. https://docs.python.org/fr/3/library/random.html#random.choice
Affichez sur la même ligne les nombres de 10 à 20 (inclus) ainsi que leur racine carrée avec 3 décimales. Utilisez pour
cela le module math avec la fonction sqrt(). Exemple : 8.8.8 Compteur de lignes
1 10 3.162 Améliorez le script compte_lignes.py dont le code a été donné précédemment de façon à ce qu’il renvoie un message
2 11 3.317
3 12 3.464 d’erreur si le fichier n’existe pas. Par exemple, si les fichiers zoo1.txt et zoo2.txt sont bien dans le répertoire courant, mais
4 13 3.606 pas zoo3.txt :
5 [...]
1 $ python compte_lignes . py zoo1 . txt
Documentation de la fonction math.sqrt() : 2 zoo1 . txt contient 4 lignes .
https://docs.python.org/fr/3/library/math.html#math.sqrt 3 $ python compte_lignes . py zoo2 . txt
4 zoo2 . txt contient 3 lignes .
5 $ python compte_lignes . py zoo3 . txt
6 ERREUR : zoo3 . txt n ' existe pas .
8.8.2 Cosinus
Calculez le cosinus de π/2 en utilisant le module math avec la fonction cos() et la constante pi.
Documentation de la fonction math.cos() : 8.8.9 Détermination du nombre pi par la méthode Monte Carlo (exercice +++)
https://docs.python.org/fr/3/library/math.html#math.cos Soit un cercle de rayon 1 (en trait plein sur la figure 8.1) inscrit dans un carré de côté 2 (en trait pointillé).
Documentation de la constante math.pi : Avec R = 1, l’aire du carré vaut (2R)2 soit 4 et l’aire du disque délimité par le cercle vaut πR2 soit π.
https://docs.python.org/fr/3/library/math.html#math.pi En choisissant N points aléatoires (à l’aide d’une distribution uniforme) à l’intérieur du carré, la probabilité que ces points
17. https://docs.python.org/fr/3/library/os.html#module-os se trouvent aussi dans le cercle est :
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 63 64 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
8.8. Exercices Chapitre 8. Modules
Chapitre 9
Fonctions
Notez que la syntaxe de def utilise les deux-points comme les boucles for et while ainsi que les tests if, un bloc En réalité Python ne renvoie qu’un seul objet, mais celui-ci peut être séquentiel, c’est-à-dire contenir lui même d’autres
d’instructions est donc attendu. De même que pour les boucles et les tests, l’indentation de ce bloc d’instructions (qu’on objets. Dans notre exemple Python renvoie un objet de type tuple, type que nous verrons dans le chapitre 13 Dictionnaires et
appelle le corps de la fonction) est obligatoire. tuples (grosso modo, il s’agit d’une sorte de liste avec des propriétés différentes). Notre fonction pourrait tout autant renvoyer
Dans l’exemple précédent, nous avons passé un argument à la fonction carre() qui nous a renvoyé (ou retourné) une une liste :
valeur que nous avons immédiatement affichée à l’écran avec l’instruction print(). Que veut dire valeur renvoyée ? Et bien 1 >>> def carre_cube2 ( x ):
cela signifie que cette dernière est récupérable dans une variable : 2 ... return [ x **2 , x **3]
3 ...
1 >>> res = carre (2) 4 >>> carre_cube2 (3)
2 >>> print ( res ) [9 , 27]
3 4 5
Ici, le résultat renvoyé par la fonction est stocké dans la variable res. Notez qu’une fonction ne prend pas forcément un Renvoyer un tuple ou une liste de deux éléments (ou plus) est très pratique en conjonction avec l’affectation multiple, par
argument et ne renvoie pas forcément une valeur, par exemple : exemple :
1 >>> def hello (): 1 >>> z1 , z2 = carre_cube2 (3)
2 ... print (" bonjour ") 2 >>> z1
3 ... 3 9
>>> hello () 4 >>> z2
4
5 bonjour 5 27
Dans ce cas la fonction, hello() se contente d’afficher la chaîne de caractères "bonjour" à l’écran. Elle ne prend aucun Cela permet de récupérer plusieurs valeurs renvoyées par une fonction et de les affecter à la volée à des variables diffé-
argument et ne renvoie rien. Par conséquent, cela n’a pas de sens de vouloir récupérer dans une variable le résultat renvoyé rentes.
par une telle fonction. Si on essaie tout de même, Python affecte la valeur None qui signifie rien en anglais :
1 >>> var = hello ()
2 bonjour 9.5 Arguments positionnels et arguments par mot-clé
3 >>> print ( var )
4 None
Jusqu’à maintenant, nous avons systématiquement passé le nombre d’arguments que la fonction attendait. Que se passe-t-il
Ceci n’est pas une faute car Python n’émet pas d’erreur, toutefois cela ne présente, la plupart du temps, guère d’intérêt. si une fonction attend deux arguments et que nous ne lui en passons qu’un seul ?
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 67 68 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
9.5. Arguments positionnels et arguments par mot-clé Chapitre 9. Fonctions Chapitre 9. Fonctions 9.6. Variables locales et variables globales
Définition Nous verrons, dans le chapitre 20 Fenêtres graphiques et Tkinter, que l’utilisation d’arguments par mot-clé est systéma-
Un argument défini avec une syntaxe def fct(arg=val): est appelé argument par mot-clé (en anglais keyword argu- tique lorsqu’on crée un objet graphique (une fenêtre, un bouton, etc.).
ment). Le passage d’un tel argument lors de l’appel de la fonction est facultatif. Ce type d’argument ne doit pas être confondu
avec les arguments positionnels présentés ci-dessus, dont la syntaxe est def fct(arg):.
Il est bien sûr possible de passer plusieurs arguments par mot-clé : 9.6 Variables locales et variables globales
1 >>> def fct ( x =0 , y =0 , z =0):
2 ... return x , y , z Lorsqu’on manipule des fonctions, il est essentiel de bien comprendre comment se comportent les variables. Une variable
3 ...
4 >>> fct () est dite locale lorsqu’elle est créée dans une fonction. Elle n’existera et ne sera visible que lors de l’exécution de ladite
5 (0 , 0 , 0) fonction.
6 >>> fct (10)
7 (10 , 0 , 0) Une variable est dite globale lorsqu’elle est créée dans le programme principal. Elle sera visible partout dans le pro-
8 >>> fct (10 , 8) gramme.
9 (10 , 8 , 0)
10 >>> fct (10 , 8 , 3) Ceci ne vous paraît pas clair ? Nous allons prendre un exemple simple qui vous aidera à mieux saisir ces concepts. Observez
11 (10 , 8 , 3) le code suivant :
On observe que pour l’instant, les arguments par mot-clé sont pris dans l’ordre dans lesquels on les passe lors de l’appel. 1 # d é finition d ' une fonction carre ()
Comment pourrions-nous faire si on souhaitait préciser l’argument par mot-clé z et garder les valeurs de x et y par défaut ? 2 def carre ( x ):
3 y = x **2
Simplement en précisant le nom de l’argument lors de l’appel : 4 return y
5
1 >>> fct ( z =10) 6 # programme principal
2 (0 , 0 , 10) 7 z = 5
8 resultat = carre ( z )
Python permet même de rentrer les arguments par mot-clé dans un ordre arbitraire : 9 print ( resultat )
1 >>> fct ( z =10 , x =3 , y =80)
(3 , 80 , 10)
2
3 >>> fct ( z =10 , y =80)
Pour la suite des explications, nous allons utiliser l’excellent site Python Tutor 1 qui permet de visualiser l’état des variables
4 (0 , 80 , 10) au fur et à mesure de l’exécution d’un code Python. Avant de poursuivre, nous vous conseillons de prendre 5 minutes pour
tester ce site.
Que se passe-t-il lorsque nous avons un mélange d’arguments positionnels et par mot-clé ? Et bien les arguments position-
nels doivent toujours être placés avant les arguments par mot-clé : Regardons maintenant ce qui se passe dans le code ci-dessus, étape par étape :
1 >>> def fct (a , b , x =0 , y =0 , z =0):
— Étape 1 : Python est prêt à lire la première ligne de code.
2 ... return a , b , x , y , z
3 ...
4 >>> fct (1 , 1) 1. http://www.pythontutor.com
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 69 70 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
9.6. Variables locales et variables globales Chapitre 9. Fonctions Chapitre 9. Fonctions 9.6. Variables locales et variables globales
— Étape 5 : Python est maintenant prêt à exécuter chaque ligne de code de la fonction.
— Étape 2 : Python met en mémoire la fonction carre(). Notez qu’il ne l’exécute pas ! La fonction est mise dans un
espace de la mémoire nommé Global frame, il s’agit de l’espace du programme principal. Dans cet espace, seront
stockées toutes les variables globales créées dans le programme. Python est maintenant prêt à exécuter le programme
principal.
— Étape 6 : La variable y est créée dans la fonction. Celle-ci est donc stockée en tant que variable locale à la fonction.
— Étape 3 : Python lit et met en mémoire la variable z. Celle-ci étant créée dans le programme principal, il s’agira d’une
variable globale. Ainsi, elle sera également stockée dans le Global frame.
— Étape 7 : Python s’apprête à renvoyer la variable locale y au programme principal. Python Tutor nous indique le
contenu de la valeur renvoyée.
— Étape 4 : La fonction carre() est appelée et on lui passe en argument l’entier z. La fonction s’exécute et un nouveau
cadre est créé dans lequel Python Tutor va indiquer toutes les variables locales à la fonction. Notez bien que la variable
passée en argument, qui s’appelle x dans la fonction, est créée en tant que variable locale. On remarquera aussi que les
variables globales situées dans le Global frame sont toujours là.
— Étape 8 : Python quitte la fonction et la valeur renvoyée par celle-ci est affectée à la variable globale resultat. Notez
bien que lorsque Python quitte la fonction, l’espace des variables alloué à la fonction est détruit. Ainsi, toutes les
variables créées dans la fonction n’existent plus. On comprend pourquoi elles portent le nom de locales puisqu’elles
n’existent que lorsque la fonction est exécutée.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 71 72 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
9.7. Principe DRY Chapitre 9. Fonctions Chapitre 9. Fonctions 9.8. Exercices
5 >>> c o n v e r t _ f a h r e n h e i t _ t o _ c e l s i u s ( t em p_ i n _ f a h re n h e i t )
6 1 5. 55 5 55 5 55 55 5 5 5 5 7
7 >>> te m p_ in _ fa h r e n h e i t = 80
8 >>> c o n v e r t _ f a h r e n h e i t _ t o _ c e l s i u s ( t em p_ i n _ f a h re n h e i t )
9 2 6 . 66 6 6 6 6 6 66 6 6 6 6 6 8
10 >>> te m p_ in _ fa h r e n h e i t = 100
11 >>> c o n v e r t _ f a h r e n h e i t _ t o _ c e l s i u s ( t em p_ i n _ f a h re n h e i t )
12 37 .77 7777 777 77 7 7 8
Et s’il y a une erreur dans la formule, il suffira de le corriger qu’une seule fois, dans la fonction convert_fahrenheit_to_celsius().
9.8 Exercices
— Étape 9 : Python affiche le contenu de la variable resultat et l’exécution est terminée. Conseil : pour le premier exercice, utilisez Python Tutor. Pour les exercices suivants, créez des scripts puis exécutez-les
dans un shell.
Malheureusement il y a une erreur dans la formule de conversion. En effet la formule exacte est :
5 9.8.2 Puissance
temp_celsius = (temp_fahrenheit − 32) ×
9
Créez une fonction calc_puissance(x, y) qui renvoie xy en utilisant l’opérateur **. Pour rappel :
Il faut alors reprendre les lignes 2, 5 et 8 précédentes et les corriger. Cela n’est pas efficace, surtout si le même code est
1 >>> 2**2
utilisé à différents endroits dans le programme. 2 4
En écrivant qu’une seule fois la formule de conversion dans une fonction, on applique le principe DRY : 3 >>> 2**3
4 8
1 >>> def c o n v e r t _ f a h r e n h e i t _ t o _ c e l s i u s ( temperature ): 5 >>> 2**4
16
... return ( temperature - 32) * (5/9)
6
2
3 ...
4 >>> te m p_ in _ fa h r e n h e it = 60 Dans le programme principal, calculez et affichez à l’écran 2i avec i variant de 0 à 20 inclus. On souhaite que le résultat
soit présenté avec le formatage suivant :
2. https://www.earthdatascience.org/courses/intro-to-earth-data-science/write-efficient-python-code/
intro-to-clean-code/dry-modular-code/ 3. http://www.pythontutor.com
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 73 74 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
9.8. Exercices Chapitre 9. Fonctions Chapitre 9. Fonctions 9.8. Exercices
1 2^ 0 = 1
2 2^ 1 = 2
3 2^ 2 = 4
4 [...]
5 2^20 = 1048576
9.8.3 Pyramide
Reprenez l’exercice du chapitre 5 Boucles et comparaisons qui dessine une pyramide.
Dans un script pyra.py, créez une fonction gen_pyramide() à laquelle vous passez un nombre entier N et qui renvoie
une pyramide de N lignes sous forme de chaîne de caractères. Le programme principal demandera à l’utilisateur le nombre de
lignes souhaitées (utilisez pour cela la fonction input()) et affichera la pyramide à l’écran.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 75 76 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
9.8. Exercices Chapitre 9. Fonctions
Remarque
Le module matplotlib sera expliqué en détail dans le chapitre 17 Quelques modules d’intérêt en bioinformatique.
Plus sur les chaînes de caractères
10.1 Préambule
Nous avons déjà abordé les chaînes de caractères dans les chapitres 2 Variables et 3 Affichage. Ici nous allons un peu plus
loin, notamment avec les méthodes associées aux chaînes de caractères 1 .
Nous pouvons donc utiliser certaines propriétés des listes comme les tranches :
1 >>> animaux = " girafe tigre "
2 >>> animaux [0:4]
3 ' gira '
4 >>> animaux [9:]
5 'gre '
6 >>> animaux [: -2]
7 ' girafe tig '
8 >>> animaux [1: -2:2]
9 ' iaetg '
Mais a contrario des listes, les chaînes de caractères présentent toutefois une différence notable, ce sont des listes non
modifiables. Une fois une chaîne de caractères définie, vous ne pouvez plus modifier un de ses éléments. Le cas échéant,
Python renvoie un message d’erreur :
1 >>> animaux = " girafe tigre "
2 >>> animaux [4]
3 'f '
4 >>> animaux [4] = " F "
5 Traceback ( most recent call last ):
6 File " < stdin >" , line 1 , in < module >
7 TypeError : 'str ' object does not support item assignment
Par conséquent, si vous voulez modifier une chaîne de caractères, vous devez en construire une nouvelle. Pour cela,
n’oubliez pas que les opérateurs de concaténation (+) et de duplication (*) (introduits dans le chapitre 2 Variables) peuvent
vous aider. Vous pouvez également générer une liste, qui elle est modifiable, puis revenir à une chaîne de caractères (voir plus
bas).
1. https://docs.python.org/fr/3/library/string.html
10.3 Caractères spéciaux L’ajout du r va forcer Python à ne pas interpréter le \n comme un retour à la ligne, mais comme un backslash littéral
suivi d’un n. Quand on demande à l’interpréteur d’afficher cette chaîne de caractères, celui-ci met deux backslashes pour
Il existe certains caractères spéciaux comme \n que nous avons déjà vu (pour le retour à la ligne). Le caractère \t produit signifier qu’il s’agit d’un backslash littéral (le premier échappe le second). Finalement, l’utilisation de la syntaxe r"Voici
une tabulation. Si vous voulez écrire des guillemets simples ou doubles et que ceux-ci ne soient pas confondus avec les un retour à la ligne\nEt là une autre ligne" renvoie une chaîne de caractères normale, puisqu’on voit ensuite
guillemets de déclaration de la chaîne de caractères, vous pouvez utiliser \' ou \". que le r à disparu lorsqu’on demande à Python d’afficher le contenu de la variable s. Comme dans var = 2 + 2, d’abord
1 >>> print (" Un retour à la ligne \ npuis une tabulation \ t puis un guillemet \"") Python évalue 2 + 2 et c’est ce résultat qui est affecté à la variable var. Enfin, on notera que seule l’utilisation du print()
2 Un retour à la ligne mène à l’interprétation des caractères spéciaux comme \n, comme expliqué dans la rubrique précédente.
3 puis une tabulation puis un guillemet "
4 >>> print ( ' J \ ' affiche un guillemet simple ') Les caractères spéciaux non interprétés dans les raw strings sont de manière générale tout ce dont le backslash modifie la
5 J ' affiche un guillemet simple signification, par exemple un \n, un \t, etc.
Vous pouvez aussi utiliser astucieusement des guillemets doubles ou simples pour déclarer votre chaîne de caractères : — Le préfixe f mis pour formatted string qui met en place l’écriture formattée comme vue au chapitre 3 Affichage :
1 >>> print (" Un brin d ' ADN ") 1 >>> animal = " renard "
2 Un brin d ' ADN 2 >>> animal2 = " poulain "
3 >>> print ( ' Python est un " super " langage de programmation ') 3 >>> s = f " Le { animal } est un animal gentil \ nLe { animal2 } aussi "
4 Python est un " super " langage de programmation 4 >>> s
5 ' Le renard est un animal gentil \ nLe poulain aussi '
Quand on souhaite écrire un texte sur plusieurs lignes, il est très commode d’utiliser les guillemets triples qui conservent 6 >>> print ( s )
7 Le renard est un animal gentil
le formatage (notamment les retours à la ligne) : 8 Le poulain aussi
9 >>> s = " Le { animal } est un animal gentil \ nLe { animal2 } aussi "
1 >>> x = """ souris 10 >>> s
2 ... chat
3 ... abeille """ 11 ' Le { animal } est un animal gentil \ nLe { animal2 } aussi '
4 >>> x 12 >>> print ( s )
5 ' souris \ nchat \ nabeille ' 13 Le { animal } est un animal gentil
6 >>> print ( x ) 14 Le { animal2 } aussi
7 souris
8 chat La f-string remplace le contenu des variables situées entre les accolades et interprète le \n comme un retour à la ligne.
9 abeille
Pour rappel, consultez le chapitre 3 si vous souhaitez plus de détails sur le fonctionnement des f-strings.
Attention, les caractères spéciaux n’apparaissent intérprétés que lorsqu’ils sont utilisés avec la fonction print(). Par
exemple, le \n n’apparait comme un saut de ligne que lorsqu’il est dans une chaîne de caractères passée à la fonction print() : Conseil
1 >>> " bla \ nbla " Il existe de nombreux autres détails concernant les préfixes qui vont au delà de ce cours. Pour en savoir plus, vous pouvez
2 ' bla \ nbla ' consulter la documentations officielle 2 .
3 >>> print (" bla \ nbla ")
4 bla
5 bla
10.4 Préfixe de chaîne de caractères 10.5 Méthodes associées aux chaînes de caractères
Voici quelques méthodes 3 spécifiques aux objets de type str :
Nous avons vu au chapitre 3 la notion de f-string. Il s’agit d’un mécanisme pour formater du texte au sein d’une chaîne de
caractères. Par exemple : 1 >>> x = " girafe "
2 >>> x . upper ()
1 >>> var = "f - string " 3 ' GIRAFE '
2 >>> f " voici une belle { var }" 4 >>> x
3 ' voici une belle f - string ' 5 ' girafe '
6 >>> ' TIGRE '. lower ()
Que signifie le f que l’on accole aux guillements de la chaîne de caractères ? Celui-ci est appelé « préfixe de chaîne de 7 ' tigre '
caractères » ou stringprefix. Les méthodes .lower() et .upper() renvoient un texte en minuscule et en majuscule respectivement. On remarque que
l’utilisation de ces méthodes n’altère pas la chaîne de caractères de départ mais renvoie une chaîne de caractères transformée.
Remarque Pour mettre en majuscule la première lettre seulement, vous pouvez faire :
Un stringprefix modifie la manière dont Python va interpréter la dite string. Celui-ci doit être systématiquement « collé » 1 >>> x [0]. upper () + x [1:]
à la chaîne de caractères, c’est-à-dire pas d’espace entre les deux. 2 ' Girafe '
1 >>> s = " Voici un retour à la ligne \ nEt l à une autre ligne " Il existe une méthode associée aux chaînes de caractères qui est particulièrement pratique, la méthode .split() :
2 >>> s
3 ' Voici un retour à la ligne \ nEt l à une autre ligne ' 1 >>> animaux = " girafe tigre singe souris "
4 >>> print ( s ) 2 >>> animaux . split ()
5 Voici un retour à la ligne 3 [ ' girafe ' , ' tigre ' , ' singe ' , ' souris ']
6 Et l à une autre ligne 4 >>> for animal in animaux . split ():
7 >>> s = r " Voici un retour à la ligne \ nEt l à une autre ligne " 5 ... print ( animal )
8 >>> s 6 ...
9 ' Voici un retour à la ligne \\ nEt l à une autre ligne '
10 >>> print ( s ) 2. https://docs.python.org/fr/3/reference/lexical_analysis.html#grammar-token-stringprefix
11 Voici un retour à la ligne \ nEt l à une autre ligne 3. https://docs.python.org/fr/3/library/string.html
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 79 80 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
10.5. Méthodes associées aux chaînes de caractères Chapitre 10. Plus sur les chaînes de caractères Chapitre 10. Plus sur les chaînes de caractères 10.6. Extraction de valeurs numériques d’une chaîne de caractères
7 girafe Cette méthode est particulièrement utile lorsqu’on lit un fichier et que l’on veut récupérer certaines lignes commençant
8 tigre
9 singe par un mot-clé. Par exemple dans un fichier PDB, les lignes contenant les coordonnées des atomes commencent par le mot-clé
10 souris ATOM.
La méthode .split() découpe une chaîne de caractères en plusieurs éléments appelés champs, en utilisant comme sépa- Enfin, la méthode .strip() permet de « nettoyer les bords » d’une chaîne de caractères :
rateur n’importe quelle combinaison « d’espace(s) blanc(s) ». 1 >>> chaine = " Comment enlever les espaces au d é but et à la fin ? "
2 >>> chaine . strip ()
3 ' Comment enlever les espaces au d é but et à la fin ? '
Définition
Un espace blanc 4 (whitespace en anglais) correspond aux caractères qui sont invisibles à l’œil, mais qui occupent de La méthode .strip() enlève les espaces situés sur les bords de la chaîne de caractère mais pas ceux situés entre des
l’espace dans un texte. Les espaces blancs les plus classiques sont l’espace, la tabulation et le retour à la ligne. caractères visibles. En réalité, cette méthode enlève n’importe quel combinaison « d’espace(s) blanc(s) » sur les bords, par
exemple :
1 >>> chaine = " \ tfonctionne avec les tabulations et les retours à la ligne \ n "
Il est possible de modifier le séparateur de champs, par exemple : 2 >>> chaine . strip ()
3 ' fonctionne avec les tabulations et les retours à la ligne '
1 >>> animaux = " girafe : tigre : singe :: souris "
2 >>> animaux . split (":") La méthode .strip() est très pratique quand on lit un fichier et qu’on veut se débarrasser des retours à la ligne.
3 [ ' girafe ' , ' tigre ' , ' singe ' , '', ' souris ']
Attention, dans cet exemple, le séparateur est un seul caractères « : » (et non pas une combinaison de un ou plusieurs :)
conduisant ainsi à une chaîne vide entre singe et souris. 10.6 Extraction de valeurs numériques d’une chaîne de caractères
Il est également intéressant d’indiquer à .split() le nombre de fois qu’on souhaite découper la chaîne de caractères avec
l’argument maxsplit : Une tâche courante en Python est de lire une chaîne de caractères (provenant par exemple d’un fichier), d’extraire des
1 >>> animaux = " girafe tigre singe souris " valeurs de cette chaîne de caractères pour ensuite les manipuler.
2 >>> animaux . split ( maxsplit =1) On considère par exemple la chaîne de caractères val :
3 [ ' girafe ' , ' tigre singe souris ']
4 >>> animaux . split ( maxsplit =2) 1 >>> val = "3.4 17.2 atom "
5 [ ' girafe ' , ' tigre ' , ' singe souris ']
On souhaite extraire les valeurs 3.4 et 17.2 pour ensuite les additionner.
La méthode .find(), quant à elle, recherche une chaîne de caractères passée en argument : Dans un premier temps, on découpe la chaîne de caractères avec la méthode .split() :
1 >>> animal = " girafe "
2 >>> animal . find (" i ") 1 >>> val2 = val . split ()
3 1 2 >>> val2
4 >>> animal . find (" afe ") 3 [ '3.4 ' , '17.2 ' , ' atom ']
5 3
6 >>> animal . find (" z ") On obtient alors une liste de chaînes de caractères. On transforme ensuite les deux premiers éléments de cette liste en
7 -1 floats (avec la fonction float()) pour pouvoir les additionner :
8 >>> animal . find (" tig ")
9 -1 1 >>> float ( val2 [0]) + float ( val2 [1])
2 2 0 .5 9 9 9 9 99 9 9 9 9 9 9 9 8
Si l’élément recherché est trouvé, alors l’indice du début de l’élément dans la chaîne de caractères est renvoyé. Si l’élément
n’est pas trouvé, alors la valeur -1 est renvoyée.
Si l’élément recherché est trouvé plusieurs fois, seul l’indice de la première occurrence est renvoyé : Remarque
1 >>> animaux = " girafe tigre " Retenez bien l’utilisation des instructions précédentes pour extraire des valeurs numériques d’une chaîne de caractères.
2 >>> animaux . find (" i ")
3 1 Elles sont régulièrement employées pour analyser des données extraites d’un fichier.
On trouve aussi la méthode .replace() qui substitue une chaîne de caractères par une autre :
1 >>> animaux = " girafe tigre "
2 >>> animaux . replace (" tigre " , " singe ")
' girafe singe '
3
4 >>> animaux . replace (" i " , " o ") 10.7 Conversion d’une liste de chaînes de caractères en une chaîne de caractères
5 ' gorafe togre '
On a vu dans le chapitre 2 Variables la conversion d’un type simple (entier, float et chaîne de caractères) en un autre avec
La méthode .count() compte le nombre d’occurrences d’une chaîne de caractères passée en argument :
les fonctions int(), float() et str(). La conversion d’une liste de chaînes de caractères en une chaîne de caractères est
>>> animaux = " girafe tigre "
particulière puisqu’elle fait appelle à la méthode .join().
1
2 >>> animaux . count (" i ")
3 2
>>> seq = [" A " , " T " , " G " , " A " , " T "]
>>> animaux . count (" z ")
1
4
>>> seq
0
2
5
[ 'A ' , 'T ' , 'G ' , 'A ' , 'T ']
>>> animaux . count (" tigre ")
3
6
7 1 4 >>> " -". join ( seq )
5 'A -T -G -A -T '
La méthode .startswith() vérifie si une chaîne de caractères commence par une autre chaîne de caractères : 6 >>> " ". join ( seq )
7 'A T G A T '
1 >>> chaine = " Bonjour monsieur le capitaine !" 8 >>> "". join ( seq )
2 >>> chaine . startswith (" Bonjour ") 9 ' ATGAT '
3 True
4 >>> chaine . startswith (" Au revoir ") Les éléments de la liste initiale sont concaténés les uns à la suite des autres et intercalés par un séparateur qui peut être
5 False
n’importe quelle chaîne de caractères. Ici, on a utilisé un tiret, un espace et rien (une chaîne de caractères vide).
4. https://en.wikipedia.org/wiki/Whitespace_character Attention, la méthode .join() ne s’applique qu’à une liste de chaînes de caractères.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 81 82 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
10.8. Exercices Chapitre 10. Plus sur les chaînes de caractères Chapitre 10. Plus sur les chaînes de caractères 10.8. Exercices
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 83 84 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
10.8. Exercices Chapitre 10. Plus sur les chaînes de caractères Chapitre 10. Plus sur les chaînes de caractères 10.8. Exercices
10.8.5 Distance de Hamming Testez ensuite si les expressions suivantes sont des pangrammes :
— Portez ce vieux whisky au juge blond qui fume
La distance de Hamming 6 mesure la différence entre deux séquences de même taille en comptant le nombre de positions
— Monsieur Jack vous dactylographiez bien mieux que votre ami Wolf
qui, pour chaque séquence, ne correspondent pas au même acide aminé.
— Buvez de ce whisky que le patron juge fameux
Créez la fonction dist_hamming() qui prend en argument deux chaînes de caractères et qui renvoie la distance de
Hamming (sous la forme d’un entier) entre ces deux chaînes de caractères.
Calculez la distance de Hamming entre les séquences
10.8.9 Lecture d’une séquence à partir d’un fichier GenBank (exercice +++)
AGWPSGGASAGLAIL et IGWPSAGASAGLWIL
puis entre les séquences On cherche à récupérer la séquence d’ADN du chromosome I de la levure Saccharomyces cerevisiae contenu dans le
ATTCATACGTTACGATT et ATACTTACGTAACCATT. fichier au format GenBank NC_001133.gbk 8 .
Le format GenBank est présenté en détails dans l’annexe A Quelques formats de données rencontrés en biologie. Pour cet
10.8.6 Palindrome exercice, vous devez savoir que la séquence démarre après la ligne commençant par le mot ORIGIN et se termine avant la ligne
commençant par les caractères // :
Un palindrome est un mot ou une phrase dont l’ordre des lettres reste le même si on le lit de gauche à droite ou de droite
1 ORIGIN
à gauche. Par exemple, « ressasser » et « engage le jeu que je le gagne » sont des palindromes. 2 1 ccacaccaca cccacacacc cacacaccac accacacacc acaccacacc cacacacaca
Créez la fonction test_palindrome() qui prend en argument une chaîne de caractères et qui affiche xxx est un 3 61 catcctaaca ctaccctaac acagccctaa tctaaccctg gccaacctgt ctctcaactt
[...]
palindrome si la chaîne de caractères xxx passée en argument est un palindrome ou xxx n'est pas un palindrome 4
5 230101 tgttagtgtt agtattaggg tgtggtgtgt gggtgtggtg tgggtgtggg tgtgggtgtg
sinon. Pensez à vous débarrasser au préalable des majuscules et des espaces. 6 230161 ggtgtgggtg tgggtgtggt gtggtgtgtg ggtgtggtgt gggtgtggtg tgtgtggg
7 //
Testez ensuite si les expressions suivantes sont des palindromes :
— radar Pour extraire la séquence d’ADN, nous vous proposons d’utiliser un algorithme de « drapeau », c’est-à-dire une variable
— never odd or even qui sera à True lorsqu’on lira les lignes contenant la séquence et à False pour les autres lignes.
— karine alla en Iran
Créez une fonction lit_genbank() qui prend comme argument le nom d’un fichier GenBank sous la forme d’une chaîne
— un roc si biscornu
de caractères, lit la séquence dans le fichier GenBank et la renvoie sous la forme d’une chaîne de caractères.
Utilisez ensuite cette fonction pour récupérer la séquence d’ADN dans la variable sequence dans le programme principal.
10.8.7 Mot composable Le script affichera :
Un mot est composable à partir d’une séquence de lettres si la séquence contient toutes les lettres du mot. Chaque lettre de 1 NC_001133 . gbk
2 La s é quence contient XXX bases
la séquence ne peut être utilisée qu’une seule fois. Par exemple, « coucou » est composable à partir de « uocuoceokzefhu ». 3 10 premi è res bases : YYYYYYYYYY
Écrivez la fonction test_composable() qui prend en argument un mot (sous la forme d’une chaîne de caractères) et 4 10 derni è res bases : ZZZZZZZZZZ
une séquence de lettres (aussi comme une chaîne de caractères) et qui affiche Le mot xxx est composable à partir
de yyy si le mot (xxx) est composable à partir de la séquence de lettres (yyy) ou Le mot xxx n'est pas composable à où XXX est un entier et YYYYYYYYYY et ZZZZZZZZZZ sont des bases.
partir de yyy sinon. Vous avez toutes les informations pour effectuer cet exercice. Si toutefois vous coincez sur la mise en place du drapeau,
Testez cette fonction avec les mots et les séquences suivantes : voici l’algorithme en pseudo-code pour vous aider :
1 drapeau <- Faux
2 seq <- cha î ne de caract è res vide
Mot Séquence 3 Lire toutes les lignes du fichier :
4 si la ligne contient //:
python aophrtkny 5 drapeau <- Faux
python aeiouyhpq 6 si drapeau est Vrai :
7 on ajoute à seq la ligne ( sans espace , chiffre et retour à la ligne )
coucou uocuoceokzezh 8 si la ligne contient ORIGIN :
fonction nhwfnitvkloco 9 drapeau <- Vrai
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 85 86 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
10.8. Exercices Chapitre 10. Plus sur les chaînes de caractères
10.8.11 Calcul des distances entre les carbones alpha consécutifs d’une structure de protéine
(exercice +++)
En utilisant la fonction trouve_calpha() précédente, calculez la distance interatomique entre les carbones alpha des
deux premiers résidus (avec deux chiffres après la virgule).
Rappel : la distance euclidienne d entre deux points A et B de coordonnées cartésiennes respectives (xA , yA , zA ) et
(xB , yB , zB ) se calcule comme suit :
q
Chapitre 11
d = (xB − xA )2 + (yB − yA )2 + (zB − zA )2
Créez ensuite la fonction calcule_distance() qui prend en argument la liste renvoyée par la fonction trouve_calpha(),
qui calcule les distances interatomiques entre carbones alpha consécutifs et affiche ces distances sous la forme : Plus sur les listes
numero_calpha_1 numero_calpha_2 distance
Les numéros des carbones alpha seront affichés sur 2 caractères. La distance sera affichée avec deux chiffres après la
virgule. Voici un exemple avec les premiers carbones alpha :
1 1 2 3.80 Nous avons vu les listes dès le chapitre 4 et les avons largement utilisées depuis le début de ce cours. Dans ce chapitre
2 2 3 3.80
3 3 4 3.83 nous allons plus loin avec les méthodes associées aux listes, ainsi que d’autres caractéristiques très puissantes telles que les
4 4 5 3.82 tests d’appartenance ou les listes de compréhension.
Modifiez maintenant la fonction calcule_distance() pour qu’elle affiche à la fin la moyenne des distances.
La distance inter-carbone alpha dans les protéines est très stable et de l’ordre de 3,8 angströms. Observez avec attention
les valeurs que vous avez calculées pour la protéine barstar. Repérez une valeur surprenante. Essayez de l’expliquer. 11.1 Méthodes associées aux listes
Conseil : vous trouverez des explications sur le format PDB et des exemples de code pour lire ce type de fichier en Python
dans l’annexe A Quelques formats de données rencontrés en biologie. Comme pour les chaînes de caractères, les listes possèdent de nombreuses méthodes qui leur sont propres et qui peuvent
se révéler très pratiques. On rappelle qu’une méthode est une fonction qui agit sur l’objet auquel elle est attachée par un point.
Contrairement aux méthodes associées aux listes présentées dans cette rubrique, del est une instruction générale de Py- 11.1.8 .count()
thon, utilisable pour d’autres objets que des listes. Celle-ci ne prend pas de parenthèse.
La méthode .count() compte le nombre d’éléments (passés en argument) dans une liste :
1 >>> a = [1 , 2 , 4 , 3 , 1 , 1]
2 >>> a . count (1)
3 3
>>> a . count (4)
11.1.4 .remove() 4
5 1
6 >>> a . count (23)
La méthode .remove() supprime un élément d’une liste à partir de sa valeur : 7 0
1 >>> a = [1 , 2 , 3]
2 >>> a . remove (3)
3 >>> a 11.1.9 Particularités des méthodes associées aux listes
4 [1 , 2]
— De nombreuses méthodes mentionnées précédemment (.append(), .sort(), etc.) modifient la liste mais ne renvoient
S’il y a plusieurs fois la même valeur dans la liste, seule la première est retirée. Il faut appeler la méthode .remove()
rien, c’est-à-dire qu’elles ne renvoient pas d’objet récupérable dans une variable. Il s’agit d’un exemple d’utilisation
autant de fois que nécessaire pour retirer toutes les occurences d’un même élément :
de méthode (donc de fonction particulière) qui fait une action mais qui ne renvoie rien. Pensez-y dans vos utilisa-
1 >>> a = [1 , 2 , 3 , 4 , 3] tions futures des listes : même si var = liste.reverse() est une instruction Python valide, elle n’a aucun intérêt,
2 >>> a . remove (3)
3 >>> a préférez-lui liste.reverse().
4 [1 , 2 , 4 , 3]
5 >>> a . remove (3)
6 >>> a Remarque
7 [1 , 2 , 4] Pour exprimer la même idée, la documentation parle de modification de la liste « sur place » (in place en anglais) :
1 >>> liste = [1 , 2 , 3]
2 >>> help ( liste . reverse )
11.1.5 .sort() 3 Help on built - in function reverse :
4
reverse () method of builtins . list instance
La méthode .sort() trie les éléments d’une liste du plus petit au plus grand : 5
6 Reverse * IN PLACE *.
1 >>> a = [3 , 1 , 2]
2 >>> a . sort () Cela signifie que la liste est modifiée « sur place », c’est-à-dire dans la méthode au moment où elle s’exécute. La liste
3 >>> a étant modifiée « en dur » dans la méthode, cette dernière ne renvoie donc rien. L’explication du mécanisme sous-jacent vous
4 [1 , 2 , 3]
sera donnée dans la rubrique 12.4 Portée des listes du chapitre 12 Plus sur les fonctions.
L’argument reverse=True spécifie le tri inverse, c’est-à-dire du plus grand au plus petit élément :
1 >>> a = [3 , 1 , 2] — Certaines méthodes ou instructions des listes décalent les indices d’une liste (par exemple .insert(), del, etc.).
2 >>> a . sort ( reverse = True )
3 >>> a — Enfin, pour obtenir une liste exhaustive des méthodes disponibles pour les listes, utilisez la fonction dir(ma_liste)
4 [3 , 2 , 1] (ma_liste étant une liste).
1 >>> a = [3 , 1 , 2] Cette méthode est certes plus simple, mais il arrive parfois qu’on doive utiliser des boucles tout de même, comme lorsqu’on
2 >>> a . reverse () lit un fichier. On rappelle que l’instruction list(seq) convertit un objet de type chaîne de caractères en un objet de type liste
>>> a
(il s’agit donc d’une opération de casting). De même que list(range(10)) convertit un objet de type range en un objet de
3
4 [2 , 1 , 3]
type list.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 89 90 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
11.3. Test d’appartenance Chapitre 11. Plus sur les listes Chapitre 11. Plus sur les listes 11.5. Liste de compréhension
L’instruction x[:] a créé une copie « à la volée » de la liste x. Vous pouvez utiliser aussi la fonction list() qui renvoie 11.5 Liste de compréhension
explicitement une liste :
1 >>> x = [1 , 2 , 3] Conseil : pour les débutants, vous pouvez passer cette rubrique.
2 >>> y = list ( x ) En Python, la notion de liste de compréhension (ou compréhension de listes) représente une manière originale et très
>>> x [1] = -15
3
4 >>> y puissante de générer des listes. La syntaxe de base consiste au moins en une boucle for au sein de crochets précédés d’une
5 [1 , 2 , 3] variable (qui peut être la variable d’itération ou pas ) :
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 91 92 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
11.6. Exercices Chapitre 11. Plus sur les listes Chapitre 11. Plus sur les listes 11.6. Exercices
11.5.4 Formatage FASTA d’une séquence (avec la ligne de commentaire) 11.6.5 Séquence d’ADN aléatoire 2
Exemple d’une séquence constituée de 150 alanines : Créez une fonction seq_alea_2() qui prend comme argument un entier et quatre floats représentant respectivement la
longueur de la séquence et les pourcentages de chacune des 4 bases A, T, G et C. La fonction générera aléatoirement une
1 >>> com = " S é quence de 150 alanines "
2 >>> seq = " A " * 150 séquence d’ADN qui prend en compte les contraintes fournies en arguments et renverra la séquence sous forme d’une liste.
3 >>> width = 60 Utilisez cette fonction pour générer aléatoirement une séquence d’ADN de 50 bases contenant 10 % de A, 30 % de T, 50
4 >>> seq_split = [ seq [ i : i + width ] for i in range (0 , len ( seq ) , width )]
5 >>> print (" >"+ com +"\ n "+"\ n ". join ( seq_split )) % de G et 10 % de C.
6 >s é quence de 150 alanines Conseil : la fonction random.shuffle() du module random vous sera utile.
7 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
8 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
9 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
11.6.6 Le nombre mystère
Trouvez le nombre mystère qui répond aux conditions suivantes :
11.5.5 Sélection des carbones alpha dans un fichier pdb — Il est composé de 3 chiffres.
— Il est strictement inférieur à 300.
Exemple avec la structure de la barstar 3 :
— Il est pair.
1 >>> with open ("1 bta . pdb " , " r ") as f_pdb : — Deux de ses chiffres sont identiques.
2 ... CA_lines = [ line for line in f_pdb if line . startswith (" ATOM ")
3 and line [12:16]. strip () == " CA "] — La somme de ses chiffres est égale à 7.
4 ... On vous propose d’employer une méthode dite « brute force », c’est-à-dire d’utiliser une boucle et à chaque itération de
5 >>> print ( len ( CA_lines )) tester les différentes conditions.
6 89
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 93 94 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
11.6. Exercices Chapitre 11. Plus sur les listes
Déduisez comment une ligne est construite à partir de la précédente. Par exemple, à partir de la ligne 2 (1 1), construisez
la ligne suivante (ligne 3 : 1 2 1) et ainsi de suite.
Implémentez cette construction en Python. Généralisez à l’aide d’une boucle.
Écrivez dans un fichier pascal.out les 10 premières lignes du triangle de Pascal.
Chapitre 12
Avant d’aborder ce chapitre, nous vous conseillons de relire le chapitre 9 Fonctions et de bien en assimiler toutes les notions
(et aussi d’en faire les exercices). Nous avons vu dans ce chapitre 9 le concept puissant et incontournable que représentent les
fonctions. Nous avons également introduit la notion de variables locales et globales.
Dans ce chapitre, nous allons aller un peu plus loin sur la visibilité de ces variables dans et hors des fonctions, et aussi voir
ce qui se passe lorsque ces variables sont des listes. Attention, la plupart des lignes de code ci-dessous sont données à titre
d’exemple pour bien comprendre ce qui se passe, mais nombre d’entre elles sont des aberrations en terme de programmation.
Nous ferons un récapitulatif des bonnes pratiques à la fin du chapitre. Enfin, nous vous conseillons de tester tous les exemples
ci-dessous avec le site Python Tutor 1 afin de suivre l’état des variables lors de l’exécution des exemples.
Nous appelons depuis le programme principal la fonction calc_vals(), puis à l’intérieur de celle-ci nous appelons
l’autre fonction polynome(). Regardons ce que Python Tutor nous montre lorsque la fonction polynome() est exécutée dans
la Figure 12.1.
L’espace mémoire alloué à polynome() est grisé, indiquant que cette fonction est en cours d’exécution. La fonction
appelante calc_vals() est toujours là (sur un fond blanc) car son exécution n’est pas terminée. Elle est en quelque sorte
figée dans le même état qu’avant l’appel de polynome(), et on pourra ainsi noter que ses variables locales (debut, fin,
liste_vals et x) sont toujours là . De manière générale, les variables locales d’une fonction ne seront détruites que lorsque
l’exécution de celle-ci sera terminée. Dans notre exemple, les variables locales de calc_vals() ne seront détruites que
lorsque la boucle sera terminée et que la liste liste_vals sera retournée au programme principal. Enfin, notez bien que la
fonction calc_vals() appelle la fonction polynome() à chaque itération de la boucle.
Ainsi, le programmeur est libre de faire tous les appels qu’il souhaite. Une fonction peut appeler une autre fonction, cette
dernière peut appeler une autre fonction et ainsi de suite (et autant de fois qu’on le veut). Une fonction peut même s’appeler
elle-même, cela s’appelle une fonction récursive (voir la rubrique suivante). Attention toutefois à retrouver vos petits si vous
vous perdez dans les appels successifs !
1. http://www.pythontutor.com/
Pas très facile à comprendre, n’est-ce pas ? À nouveau, nous nous aidons de Python Tutor pour visualiser ce qui se passe Lorsque Python exécute le code de la fonction, il connaît le contenu de la variable x. Par contre, de retour dans le module
dans la figure 12.2 (nous vous conseillons bien sûr de tester vous-même cet exemple) : principal (dans ce cas, il s’agit de l’interpréteur Python), il ne la connaît plus, d’où le message d’erreur.
Ligne 8, on appelle la fonction calc_factorielle() en passant comme argument l’entier 4. Dans la fonction, la variable De même, une variable passée en argument est considérée comme locale lorsqu’on arrive dans la fonction :
locale qui récupère cet argument est nb. Au sein de la fonction, celle-ci se rappelle elle-même (ligne 5), mais cette fois-ci en 1 >>> def ma_fonction ( x ):
passant la valeur 3. Au prochain appel, ce sera avec la valeur 2, puis finalement 1. Dans ce dernier cas, le test if nb == 1: 2 ... print ( f " x vaut { x } dans la fonction ")
...
est vrai et l’instruction return 1 sera exécutée. À ce moment précis de l’exécution, les appels successifs forment une sorte 3
4 >>> ma_fonction (2)
de pile (voir la figure 12.2). La valeur 1 sera ainsi renvoyée au niveau de l’appel précédent, puis le résultat 2 × 1 = 2 (où 2 5 x vaut 2 dans la fonction
correspond à nb et 1 provient de calc_factorielle(nb - 1) soit 1) va être renvoyé à l’appel précédent, puis 3 × 2 = 6 6 >>> print ( x )
7 Traceback ( most recent call last ):
(où 3 correspond à nb et 2 provient de calc_factorielle(nb - 1) soit 2) va être renvoyé à l’appel précédent, pour finir 8 File " < stdin >" , line 1 , in ?
par 4 × 6 = 24 (où 4 correspond à nb et 6 provient de calc_factorielle(nb - 1) soit 6), soit la valeur de 4!. Les appels 9 NameError : name 'x ' is not defined
successifs vont donc se « dépiler » et nous reviendrons dans le programme principal. Lorsqu’une variable est déclarée dans le programme principal, elle est visible dans celui-ci ainsi que dans toutes les
2. https://fr.wikipedia.org/wiki/Tri_rapide fonctions. On a vu qu’on parlait de variable globale :
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 97 98 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
12.4. Portée des listes Chapitre 12. Plus sur les fonctions Chapitre 12. Plus sur les fonctions 12.5. Règle LGI
Dans ce cas, la variable x est visible dans le module principal et dans toutes les fonctions du module. Toutefois, Python ne
permet pas la modification d’une variable globale dans une fonction :
1 >>> def ma_fonction ():
2 ... x = x + 1
3 ...
4 >>> x = 1
5 >>> ma_fonction ()
6 Traceback ( most recent call last ):
7 File " < stdin >" , line 1 , in < module >
8 File " < stdin >" , line 2 , in fct
9 Un bou ndLo cal Er r o r : local variable 'x ' referenced before assignment
F IGURE 12.3 – Passage d’une liste à une fonction.
L’erreur renvoyée montre que Python pense que x est une variable locale qui n’a pas été encore assignée. Si on veut
vraiment modifier une variable globale dans une fonction, il faut utiliser le mot-clé global :
1 >>> def ma_fonction (): liste_tmp, on modifie aussi liste. C’est exactement le même mécanisme que pour la copie de listes (cf. rubrique 11.4
2 ... global x
3 ... x = x + 1 Copie de listes du chapitre 11 Plus sur les listes).
4 ... Si vous voulez éviter les problèmes de modification malencontreuse d’une liste dans une fonction, utilisez des tuples (ils
5 >>> x = 1
6 >>> ma_fonction () seront présentés dans le chapitre 13 Dictionnaires et tuples), Python renverra une erreur car ces derniers sont non modifiables.
7 >>> x Une autre solution pour éviter la modification d’une liste, lorsqu’elle est passée comme argument à une fonction, est de la
8 2
passer explicitement (comme nous l’avons fait pour la copie de liste) afin qu’elle reste intacte dans le programme principal.
Dans ce dernier cas, le mot-clé global a forcé la variable x à être globale plutôt que locale au sein de la fonction.
1 >>> def ma_fonction ( x ):
2 ... x [1] = -15
3 ...
12.4 Portée des listes 4
5
>>>
>>>
y = [1 , 2 , 3]
ma_fonction ( y [:])
6 >>> y
7 [1 , 2 , 3]
8 >>> ma_fonction ( list ( y ))
Attention 9 >>> y
Les exemples de cette partie représentent des absurdités en termes de programmation. Ils sont donnés à titre indicatif pour 10 [1 , 2 , 3]
comprendre ce qui se passe, mais il ne faut surtout pas s’en inspirer !
Dans ces deux derniers exemples, une copie de y est créée à la volée lorsqu’on appelle la fonction, ainsi la liste y du
module principal reste intacte.
Soyez extrêmement attentifs avec les types modifiables (tels que les listes) car vous pouvez les changer au sein d’une D’autres suggestions sur l’envoi de liste dans une fonction vous sont données dans la rubrique Recommandations ci-
fonction : dessous.
1 >>> def ma_fonction ():
2 ... liste [1] = -127
3 ...
4 >>> liste = [1 ,2 ,3] 12.5 Règle LGI
5 >>> ma_fonction ()
6 >>> liste
7 [1 , -127 , 3] Lorsque Python rencontre une variable, il va traiter la résolution de son nom avec des priorités particulières. D’abord il
va regarder si la variable est locale, puis si elle n’existe pas localement, il vérifiera si elle est globale et enfin si elle n’est pas
De même, si vous passez une liste en argument, elle est modifiable au sein de la fonction :
globale, il testera si elle est interne (par exemple la fonction len() est considérée comme une fonction interne à Python, elle
1 >>> def ma_fonction ( x ):
2 ... x [1] = -15
existe à chaque fois que vous lancez Python). On appelle cette règle la règle LGI pour locale, globale, interne. En voici un
3 ... exemple :
4 >>> y = [1 ,2 ,3]
5 >>> ma_fonction ( y ) 1 >>> def ma_fonction ():
6 >>> y 2 ... x = 4
7 [1 , -15 , 3] 3 ... print ( f " Dans la fonction x vaut { x }")
4 ...
Pour bien comprendre l’origine de ce comportement, utilisons à nouveau le site Python Tutor 3 . La figure 12.3 vous montre 5 >>> x = -15
6 >>> ma_fonction ()
le mécanisme à l’oeuvre lorsqu’on passe une liste à une fonction. 7 Dans la fonction x vaut 4
L’instruction pass dans la fonction est une instruction Python qui ne fait rien. Elle est là car une fonction ne peut être vide 8 >>> print ( f " Dans le module principal x vaut { x }")
9 Dans le module principal x vaut -15
et doit contenir au moins une instruction Python valide.
On voit très clairement que la variable liste passée en argument lors de l’appel de la fonction d’une part, et la variable Dans la fonction, x a pris la valeur qui lui était définie localement en priorité sur la valeur définie dans le module principal.
locale liste_tmp au sein de la fonction d’autre part, pointent vers le même objet dans la mémoire. Ainsi, si on modifie
3. http://www.pythontutor.com/ Conseil
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 99 100 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
12.6. Recommandations Chapitre 12. Plus sur les fonctions Chapitre 12. Plus sur les fonctions 12.7. Exercices
Même si Python peut reconnaître une variable ayant le même nom que ses propres fonctions ou variables internes, évitez Conseil
de les utiliser car ceci rendra votre code confus ! Pour les raisons évoquées ci-dessus, nous vous conseillons de privilégier la première version :
1 liste_notes = ajoute_un ( liste_notes )
De manière générale la règle LGI découle de la manière dont Python gère ce que l’on appelle « les espaces de noms ».
C’est cette gestion qui définit la portée (visibilité) de chaque variable. Nous en parlerons plus longuement dans le chapitre 19
Avoir la classe avec les objets.
12.6.3 Conclusion
12.6 Recommandations Vous connaissez maintenant les fonctions sous tous leurs angles. Comme indiqué en introduction du chapitre 9, elles sont
incontournables et tout programmeur se doit de les maîtriser. Voici les derniers conseils que nous pouvons vous donner :
12.6.1 Évitez les variables globales — Lorsque vous débutez un nouveau projet de programmation, posez-vous la question : « Comment pourrais-je décom-
poser en blocs chaque tâche à effectuer, chaque bloc pouvant être une fonction ? ». Et n’oubliez pas que si une fonction
Dans ce chapitre nous avons joué avec les fonctions (et les listes) afin de vous montrer comment Python réagissait. Toute- s’avère trop complexe, vous pouvez la décomposer en d’autres fonctions.
fois, notez bien que l’utilisation de variables globales est à bannir définitivement de votre pratique de la programmation. — Au risque de nous répéter, forcez-vous à utiliser des fonctions en permanence. Pratiquez, pratiquez. . . et pratiquez
Parfois on veut faire vite et on crée une variable globale visible partout dans le programme (donc dans toutes les fonctions), encore !
car « Ça va plus vite, c’est plus simple ». C’est un très mauvais calcul, ne serait-ce que parce que vos fonctions ne seront pas
réutilisables dans un autre contexte si elles utilisent des variables globales ! Ensuite, arriverez-vous à vous relire dans six
mois ? Quelqu’un d’autre pourrait-il comprendre votre programme ? Il existe de nombreuses autres raisons 4 que nous ne 12.7 Exercices
développerons pas ici, mais libre à vous de consulter de la documentation externe.
Heureusement, Python est orienté objet et permet « d’encapsuler » des variables dans des objets et de s’affranchir défini- Conseil : pour le second exercice, créez un script puis exécutez-le dans un shell.
tivement des variables globales (nous verrons cela dans le chapitre 19 Avoir la classe avec les objets). En attendant, et si vous
ne souhaitez pas aller plus loin sur les notions d’objet (on peut tout à fait « pythonner » sans cela), retenez la chose suivante 12.7.1 Prédire la sortie
sur les fonctions et les variables globales :
Prédisez le comportement des codes suivants, sans les recopier dans un script ni dans l’interpréteur Python :
Conseil
Plutôt que d’utiliser des variables globales, passez vos variables explicitement aux fonctions comme des argument(s). Code 1
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 101 102 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
12.7. Exercices Chapitre 12. Plus sur les fonctions
8 x = 10
9 hello (" Patrick ")
10 print ( x )
13.1 Containers
13.1.1 Définition
Définition
Un container est un nom générique pour définir un objet Python qui contient une collection d’autres objets.
Les containers que nous connaissons depuis le début de ce cours sont les listes et les chaînes de caractères. Même si on ne
l’a pas vu explicitement, les objets de type range sont également des containers.
Dans la section suivante, nous allons examiner les différentes propriétés des containers. A la fin de ce chapitre, nous ferons
un tableau récapitulatif de ces propriétés.
13.1.2 Propriétés
Examinons d’abord les propriétés qui caractérisent tous les types de container.
— Capacité à supporter le test d’appartenance. Souvenez-vous, il permettait de vérifier si un élément était présent dans
une liste. Cela fonctionne donc aussi sur les chaînes de caractères ou tout autre container :
1 >>> l = [1 , 2 , 3]
2 >>> 1 in l
3 True
4 >>> " to " in " toto "
5 True
Définition
Un objet séquentiel ou séquence est un container itérable, ordonné et indexable. Les objets séquentiels sont les listes, les
chaînes de caractères, les objets de type range, ainsi que les tuples (cf. plus bas).
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 103 104
13.1. Containers Chapitre 13. Containers, dictionnaires, tuples et sets Chapitre 13. Containers, dictionnaires, tuples et sets 13.1. Containers
Une autre propriété importante que l’on a déjà croisée et qui nous servira dans ce chapitre concerne la possiblité ou non L’identifiant est quant à lui attribué par Python à la création de l’objet. Il est constant tout le le long de la durée de vie de
de modifier un objet. l’objet, un peu comme une carte d’identité. Tout objet a un un identifiant, mais il doit être hachable pour avoir une valeur de
— Un objet est dit non modifiable lorsqu’on ne peut pas le modifier, ou lorsqu’on ne peut pas en modifier un de ses hachage.
éléments si c’est un container. On parle aussi d’objet immuable 1 (immutable object en anglais). Cela signifie qu’une
fois créé, Python ne permet plus de le modifier par la suite.
Qu’en est-il des objets que nous connaissons ? Les listes sont modifiables, on peut modifier un ou plusieurs de ses éléments.
Tous les autres types que nous avons vus précédemment sont quant à eux non modifiables : les chaînes de caractères ou strings, Pour aller plus loin
les objets de type range, mais également des objets qui ne sont pas des containers comme les entiers, les floats et les booléens.
Pour aller plus loin, vous pouvez consulter la page Wikipedia sur les fonctions de hachage 2 .
On comprend bien l’immutabilité des strings comme vu au chapitre 10, mais c’est moins évident pour les entiers, floats
ou booléens. Nous allons démontrer cela, mais avant nous avons besoin de définir la notion d’identifiant d’un objet.
Pourquoi évoquer cette propriété de hachabilité ? D’abord, parce-qu’elle est étroitement liée à l’immutabilité. En effet, un
Définition objet non modifiable est la plupart du temps hachable. Cela permet de l’identifier en fonction de son contenu. Par ailleurs,
L’identifiant d’un objet est un nombre entier qui est garanti constant pendant toute la durée de vie de l’objet. Cet identifiant l’hachabilité est une implémentation qui permet un accès rapide aux éléments des containers de type dictionnaire ou set
est en général unique pour chaque objet. Toutefois, pour des raisons d’optimisation, Python crée parfois le même identifiant (cf. rubriques suivantes).
pour deux objets non modifiables différents qui ont la même valeur. L’identifiant peut être assimilé à l’adresse mémoire de
l’objet qui elle aussi est unique. En Python, on utilise la fonction interne id() qui prend en argument un objet et renvoie son Les objets hachables sont les chaînes de caractères, les entiers, les floats, les booléens, les objets de type range, les
identifiant. tuples (sous certaines conditions) et les frozensets ; par contre, les listes, les sets et les dictionnaires sont non hachables. Les
dictionnaires, tuples, sets et frozensets seront vus plus bas dans ce chapitre.
Voici un exemple :
Maintenant que l’identifiant est défini, regardons l’exemple suivant qui montre l’immutabilité des entiers.
1 >>> hash (" Plouf ")
1 >>> a = 4 2 5 0 8 5 6 4 8 80 5 2 6 0 2 1 0 7 1 8
2 >>> id ( a ) 3 >>> hash (5)
3 140318876873440 4 5
4 >>> a = 5 5 >>> hash (3.14)
5 >>> id ( a ) 6 3 22 8 18 02 1 28 9 91 7 4 4 3
6 140318876873472 7 >>> hash ([1 , 2 , 3])
Traceback ( most recent call last ):
En ligne 1 on définit l’entier a puis on regarde son identifiant. En ligne 4, on pourrait penser que l’on modifie a. Toutefois,
8
9 File " < stdin >" , line 1 , in < module >
on voit que son identifiant en ligne 6 est différent de la ligne 3. En fait, l’affectation en ligne 4 a = 5 écrase l’ancienne variable 10 TypeError : unhashable type : ' list '
a et en crée une nouvelle, ce n’est pas la valeur de a qui a été changée puisque l’identifiant n’est plus le même. Le même
raisonnement peut être tenu pour les autres types numériques comme les floats et booléens. Si on regarde maintenant ce qu’il Les valeurs de hachage renvoyées par la fonction hash() de Python sont systématiquement des entiers. Par contre, Python
se passe pour une liste : renvoie une erreur pour une liste car elle est non hachable.
1 >>> l = [1 , 2 , 3]
2 >>> id ( l )
3 14031885032483 2
4 >>> l [1] = -15 13.1.3 Containers de type range
5 >>> id ( l )
6 14031885032483 2
7 >>> l . append (5) Revenons rapidement sur les objets de type range. Jusqu’à maintenant, on s’en est servi pour faire des boucles ou générer
8 >>> id ( l ) des listes de nombres. Toutefois, on a vu ci-dessus qu’ils étaient aussi des containers. Ils sont ordonnés, indexables, itérables,
9 14031885032483 2
hachables et non modifiables.
La liste l a été modifiée en ligne 4 (changement de l’élément d’indice 1) et en ligne 7 (ajout d’un élément). Pour autant,
1 >>> r = range (3)
l’identifiant de cette liste est resté identique tout du long. Ceci démontre la mutabilité des listes : quelle que soit la manière 2 >>> r [0]
dont on modifie une liste, celle-ci garde le même identifiant. 3 0
4 >>> r [0:1]
— Une dernière propriété importante est la capacité d’un container (ou tout autre objet Python) à être hachable. 5 range (0 , 1)
6 >>> for i in r :
7 ... print ( i )
Définition 8 ...
Un objet Python est dit hachable (hashable en anglais) s’il est possible de calculer une valeur de hachage sur celui-ci 9 0
10 1
avec la fonction interne hash(). En programmation, la valeur de hachage peut être vue comme une empreinte numérique de 11 2
l’objet. Elle est obtenue en passant l’objet dans une fonction de hachage et dépend du contenu de l’objet. En Python, cette 12 >>> r [2] = 10
13 Traceback ( most recent call last ):
empreinte est comme dans la plupart des langages de programmation un entier. Au sein d’une même session Python, deux 14 File " < stdin >" , line 1 , in < module >
objets hachables qui ont un contenu identique auront strictement la même valeur de hachage. 15 TypeError : ' range ' object does not support item assignment
16 >>> hash ( r )
17 5 0 5 0 9 0 7 0 6 1 2 01 6 4 7 0 9 7
La tentative de modification d’un élément en ligne 12 conduit à la même erreur que lorsqu’on essaie de modifier un
Attention caractère d’une chaîne de caractères. Comme pour la plupart des objets Python non modifiables, les objets de type range sont
La valeur de hachage d’un objet renvoyée par la fonction hash() n’a pas le même sens que son identifiant renvoyé par hachables.
la fonction id(). La valeur de hachage est obtenue en « moulinant » le contenu de l’objet dans une fonction de hachage.
1. https://fr.wikipedia.org/wiki/Objet_immuable 2. https://fr.wikipedia.org/wiki/Fonction_de_hachage
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 105 106 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
13.2. Dictionnaires Chapitre 13. Containers, dictionnaires, tuples et sets Chapitre 13. Containers, dictionnaires, tuples et sets 13.2. Dictionnaires
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 107 108 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
13.2. Dictionnaires Chapitre 13. Containers, dictionnaires, tuples et sets Chapitre 13. Containers, dictionnaires, tuples et sets 13.2. Dictionnaires
1 >>> ani2 = { ' nom ': ' singe ' , ' poids ': 70 , ' taille ': 1.75} 1 >>> dico = {" a ": 15 , " b ": 5 , " c ":20}
2 >>> if " poids " in ani2 : 2 >>> for key in sorted ( dico , key = dico . get ):
3 ... print (" La cl é ' poids ' existe pour ani2 ") 3 ... print ( key , dico [ key ])
4 ... 4 ...
5 La cl é ' poids ' existe pour ani2 5 b 5
6 >>> if " age " in ani2 : 6 a 15
7 ... print (" La cl é 'age ' existe pour ani2 ") 7 c 20
8 ...
Enfin, l’argument reverse=True fonctionne également :
Dans le second test (lignes 5 à 7), le message n’est pas affiché car la clé age n’est pas présente dans le dictionnaire ani2.
1 >>> dico = {" a ": 15 , " b ": 5 , " c ":20}
Si on souhaite tester si une valeur existe dans un dictionnaire, on peut utiliser l’opérateur in avec l’objet renvoyé par la 2 >>> sorted ( dico , key = dico . get , reverse = True )
méthode .values() : 3 [ 'c ' , 'a ' , 'b ']
1 >>> ani2 = { ' nom ': ' singe ' , ' poids ': 70 , ' taille ': 1.75}
2 >>> ani2 . values ()
3 dict_values ([ ' singe ' , 70 , 1.75]) Remarque
4 >>> " singe " in ani2 . values () Lorsqu’on trie un dictionnaire par ses valeurs, il faut être sûr que cela soit possible. Ce n’est, par exemple, pas le cas pour
5 True
le dictionnaire ani2 car les valeurs sont des valeurs numériques et une chaîne de caractères :
1 >>> ani2 = { ' nom ': ' singe ' , ' poids ': 70 , ' taille ': 1.75}
2 >>> sorted ( ani2 , key = ani2 . get )
13.2.6 Méthode .get() 3 Traceback ( most recent call last ):
4 File " < stdin >" , line 1 , in < module >
5 TypeError : '<' not supported between instances of 'int ' and 'str '
Par défaut, si on demande la valeur associée à une clé qui n’existe pas, Python renvoie une erreur :
1 >>> ani2 = { ' nom ': ' singe ' , ' poids ': 70 , ' taille ': 1.75} On obtient ici une erreur car Python ne sait pas comparer une chaîne de caractères (singe) avec des valeurs numériques
2 >>> ani2 [" age "] (70 et 1.75).
3 Traceback ( most recent call last ):
4 File " < stdin >" , line 1 , in < module >
5 KeyError : 'age '
La méthode .get() s’affranchit de ce problème. Elle extrait la valeur associée à une clé mais ne renvoie pas d’erreur si la
clé n’existe pas :
13.2.9 Clé associée au minimum ou au maximum des valeurs
1 >>> ani2 . get (" nom ") Les fonctions min() et max(), que vous avez déjà manipulées dans les chapitres précédents, acceptent également l’argu-
2 ' singe ' ment key=. On peut ainsi obtenir la clé associée au minimum ou au maximum des valeurs d’un dictionnaire :
3 >>> ani2 . get (" age ")
4 >>> 1 >>> dico = {" a ": 15 , " b ": 5 , " c ":20}
2 >>> max ( dico , key = dico . get )
Ici la valeur associée à la clé nom est singe mais la clé age n’existe pas. On peut également indiquer à .get() une valeur 3 'c '
4 >>> min ( dico , key = dico . get )
par défaut si la clé n’existe pas : 5 'b '
1 >>> ani2 . get (" age " , 42)
2 42
13.2.10 Liste de dictionnaires
En créant une liste de dictionnaires qui possèdent les mêmes clés, on obtient une structure qui ressemble à une base de
13.2.7 Tri par clés données :
On peut utiliser la fonction sorted() vue précédemment avec les listes pour trier un dictionnaire par ses clés : 1 >>> animaux = [ ani1 , ani2 ]
2 >>> animaux
1 >>> ani2 = { ' nom ': ' singe ' , ' taille ': 1.75 , ' poids ': 70} 3 [{ ' nom ': ' girafe ' , ' poids ': 1100 , ' taille ': 5.0} , { ' nom ': ' singe ' ,
2 >>> sorted ( ani2 ) 4 ' poids ': 70 , ' taille ': 1.75}]
3 [ ' nom ' , ' poids ' , ' taille '] 5 >>>
6 >>> for ani in animaux :
7 ... print ( ani [" nom "])
Les clés sont triées ici par ordre alphabétique. 8 ...
9 girafe
10 singe
13.2.8 Tri par valeurs Vous constatez ainsi que les dictionnaires permettent de gérer des structures complexes de manière plus explicite que les
Pour trier un dictionnaire par ses valeurs, il faut utiliser la fonction sorted avec l’argument key : listes.
1 >>> dico = {" a ": 15 , " b ": 5 , " c ":20}
2 >>> sorted ( dico , key = dico . get ) 13.2.11 Fonction dict()
3 [ 'b ' , 'a ' , 'c ']
Conseil : Pour les débutants vous pouvez sauter cette rubrique.
L’argument key=dico.get indique explicitement qu’il faut réaliser le tri par les valeurs du dictionnaire. On retrouve La fonction dict() va convertir l’argument qui lui est passé en dictionnaire. Il s’agit donc d’une fonction de casting
la méthode .get() vue plus haut, mais sans les parenthèses : key=dico.get mais pas key=dico.get(). Une fonction comme int(), str(), etc. Toutefois, l’argument qui lui est passé doit avoir une forme particulière : un objet séquentiel
ou méthode passée en argument sans les parenthèses est appelée callback, nous reverrons cela en détail dans le chapitre 20 contenant d’autres objets séquentiels de 2 éléments. Par exemple, une liste de listes de 2 éléments :
Fenêtres graphiques et Tkinter.
1 >>> liste_animaux = [[" girafe " , 2] , [" singe " , 3]]
Attention, ce sont les clés du dictionnaires qui sont renvoyées, pas les valeurs. Ces clés sont cependant renvoyées dans un 2 >>> dict ( liste_animaux )
ordre qui permet d’obtenir les clés triées par ordre croissant : 3 { ' girafe ': 2 , ' singe ': 3}
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 109 110 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
13.3. Tuples Chapitre 13. Containers, dictionnaires, tuples et sets Chapitre 13. Containers, dictionnaires, tuples et sets 13.3. Tuples
Ou un tuple de tuples de 2 éléments (cf. rubrique suivante pour la définition d’un tuple), ou encore une combinaison liste Autre particularité des tuples, il est possible de les créer sans les parenthèses, dès lors que ceci ne pose pas d’ambiguïté
/ tuple : avec une autre expression :
1 >>> tuple_animaux = ((" girafe " , 2) , (" singe " , 3)) 1 >>> t = (1 , 2 , 3)
2 >>> dict ( tuple_animaux ) 2 >>> t
3 { ' girafe ': 2 , ' singe ': 3} 3 (1 , 2 , 3)
4 >>> 4 >>> t = 1, 2, 3
5 >>> dict ([(" girafe " , 2) , (" singe " , 3)]) 5 >>> t
6 { ' girafe ': 2 , ' singe ': 3} 6 (1 , 2 , 3)
Si un des sous-éléments a plus de 2 éléments (ou moins), Python renvoie une erreur : Toutefois, afin d’éviter les confusions, nous vous conseillons d’utiliser systématiquement les parenthèses lorsque vous
débutez.
1 >>> dict ([(" girafe " , 2) , (" singe " , 3 , 4)])
2 Traceback ( most recent call last ):
3 File " < stdin >" , line 1 , in < module >
4 ValueError : dictionary update sequence element #1 has length 3; 2 is required Les opérateurs + et * fonctionnent comme pour les listes (concaténation et duplication) :
1 >>> (1 , 2) + (3 , 4)
2 (1 , 2 , 3 , 4)
>>> (1 , 2) * 4
13.3 Tuples 3
4 (1 , 2 , 1 , 2 , 1 , 2 , 1 , 2)
13.3.1 Définition Enfin, on peut utiliser la fonction tuple(sequence) qui fonctionne exactement comme la fonction list(), c’est-à-dire
qu’elle prend en argument un objet de type container et renvoie le tuple correspondant (opération de casting) :
Les tuples (« n-uplets » en français) sont des objets séquentiels correspondant aux listes (itérables, ordonnés et indexables) 1 >>> tuple ([1 ,2 ,3])
mais ils sont toutefois non modifiables. On verra plus bas qu’ils sont hachables sous certaines conditions. L’intérêt des tuples 2 (1 , 2 , 3)
par rapport aux listes réside dans leur immutabilité. Cela, accèlère considérablement la manière dont Python accède à chaque 3 >>> tuple (" ATGCCGCGAT ")
4 ( 'A ' , 'T ' , 'G ' , 'C ' , 'C ' , 'G ' , 'C ' , 'G ' , 'A ' , 'T ')
élément et ils prennent moins de place en mémoire. Par ailleurs, on ne risque pas de modifier un de ses éléments par mégarde.
Vous verrez ci-dessous que nous les avons déjà croisés à plusieurs reprises !
Pratiquement, on utilise les parenthèses au lieu des crochets pour les créer : Remarque
1 >>> t = (1 , 2 , 3) Les listes, les dictionnaires et les tuples sont des containers, c’est-à-dire qu’il s’agit d’objets qui contiennent une collection
2 >>> t d’autres objets. En Python, on peut construire des listes qui contiennent des dictionnaires, des tuples ou d’autres listes, mais
3 (1 , 2 , 3)
4 >>> type ( t ) aussi des dictionnaires contenant des tuples, des listes, etc. Les combinaisons sont infinies !
5 < class ' tuple ' >
6 >>> t [2]
7 3
8 >>> t [0:2]
9 (1 , 2)
10 >>> t [2] = 15 13.3.2 Itérations sur plusieurs valeurs à la fois
11 Traceback ( most recent call last ):
12 File " < stdin >" , line 1 , in < module > Pratiquement, nous avons déjà croisé les tuples avec la fonction enumerate() dans le chapitre 5 Boucles et comparaisons.
13 TypeError : ' tuple ' object does not support item assignment
Cette dernière permettait d’itérer en même temps sur les indices et les éléments d’une liste :
L’affectation et l’indiçage fonctionnent comme avec les listes. Mais si on essaie de modifier un des éléments du tuple (en 1 >>> for indice , element in enumerate ([75 , -75 , 0]):
ligne 10), Python renvoie un message d’erreur. Ce message est similaire à celui que nous avions rencontré quand on essayait de 2 ... print ( indice , element )
3 ...
modifier une chaîne de caractères (cf. chapitre 10). De manière générale, Python renverra un message TypeError: '[...]' 4 0 75
1 -75
does not support item assignment lorsqu’on essaie de modifier un élément d’un objet non modifiable. Si vous voulez 5
6 2 0
ajouter un élément (ou le modifier), vous devez créer un nouveau tuple : 7 >>> for bidule in enumerate ([75 , -75 , 0]):
8 ... print ( bidule , type ( bidule ))
1 >>> t = (1 , 2 , 3) 9 ...
2 >>> t 10 (0 , 75) < class ' tuple ' >
3 (1 , 2 , 3) 11 (1 , -75) < class ' tuple ' >
4 >>> id ( t ) 12 (2 , 0) < class ' tuple ' >
5 139971081704464
>>> t = t + (2 ,)
6
7 >>> t En fin de compte, la fonction enumerate() itère sur une série de tuples. Pouvoir séparer indice et element dans la
8 (1 , 2 , 3 , 2) boucle est possible du fait que Python autorise l’affectation multiple du style indice, element = 0, 75 (voir rubrique
9 >>> id ( t ) suivante).
10 139971081700368
Dans le même ordre d’idée, nous avons vu précédemment la méthode .dict_items() qui permettait d’itérer sur des
La fonction id() montre que le tuple créé en ligne 6 est bien différent de celui créé en ligne 4 bien qu’ils aient le même couples clé / valeur d’un dictionnaire :
nom. Comme on a vu plus haut, ceci est dû à l’opérateur d’affectation utilisé en ligne 6 (t = t + (2,)) qui crée un nouvel 1 >>> dico = {" pinson ": 2 , " merle ": 3}
objet distinct de celui de la ligne 1. Cet exemple montre que les tuples sont peu adaptés lorsqu’on a besoin d’ajouter, retirer, 2 >>> for cle , valeur in dico . items ():
modifier des éléments. La création d’un nouveau tuple à chaque étape s’avère lourde et il n’y a aucune méthode pour faire 3 ... print ( cle , valeur )
4 ...
cela puisque les tuples sont non modifiables. Pour ce genre de tâche, les listes sont clairement mieux adaptées. 5 pinson 2
6 merle 3
7 >>> for bidule in dico . items ():
Remarque 8 ... print ( bidule , type ( bidule ))
...
Pour créer un tuple d’un seul élément comme ci-dessus, utilisez une syntaxe avec une virgule (element,), pour éviter
9
10 ( ' pinson ' , 2) < class ' tuple ' >
une ambiguïté avec une simple expression. Par exemple (2) équivaut à l’entier 2, (2,) est un tuple avec l’élément 2. 11 ( ' merle ' , 3) < class ' tuple ' >
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 111 112 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
13.3. Tuples Chapitre 13. Containers, dictionnaires, tuples et sets Chapitre 13. Containers, dictionnaires, tuples et sets 13.3. Tuples
La méthode .dict_items() itère comme enumerate() sur une série de tuples. Cela envoie le message à celui qui lit le code « je me fiche des valeurs récupérées dans ces variables _ ». Notez que
De la même façon, on peut itérer sur 3 valeurs en même temps à partir d’une liste de tuples de 3 éléments : l’on peut utiliser une ou plusieurs variables underscores(s). Dans l’exemple ci-dessus, la 2e et la 4e variable renvoyées par la
1 >>> liste = [( i , i +1 , i +2) for i in range (5 , 8)] fonction seront ignorées dans la suite du code. Cela a le mérite d’éviter de polluer l’attention du lecteur du code.
2 >>> liste
3 [(5 , 6 , 7) , (6 , 7 , 8) , (7 , 8 , 9)]
4 >>> for x , y , z in liste : Remarque
... print (x , y , z )
Dans l’interpréteur interactif, la variable _ a une signication différente. Elle prend automatiquement la dernière valeur
5
6 ...
7 5 6 7 affichée :
8 6 7 8
9 7 8 9 1 >>> 3
2 3
On pourrait concevoir la même chose sur 4, 5. . . éléments. La seule contrainte est d’avoir une correspondance systématique 3 >>> _
3
entre le nombre de variables d’itération (par exemple 3 variables dans l’exemple ci-dessus avec x, y, z) et la longueur de 4
5 >>> " m é sange "
chaque sous-tuple de la liste sur laquelle on itère (chaque sous-tuple a 3 éléments ci-dessus). 6 'm é sange '
7 >>> _
8 'm é sange '
13.3.3 Affectation multiple et le nom de variable _
Attention, cela n’est vrai que dans l’interpréteur !
L’affectation multiple est un mécanisme très puissant et important en Python. Pour rappel, il permet d’effectuer sur une
même ligne plusieurs affectations en même temps, par exemple : x, y, z = 1, 2, 3. Cette syntaxe correspond à un tuple
de chaque côté de l’opérateur =. Notez qu’il serait possible de le faire également avec les listes : [x, y, z] = [1, 2, 3].
Toutefois, cette syntaxe est alourdie par la présence des crochets. On préfèrera donc la première syntaxe avec les tuples sans Remarque
parenthèse. Le caractère underscore (_) est couramment utilisé dans les noms de variable pour séparer les mots et être explicite, par
exemple seq_ADN ou liste_listes_residus. On verra dans le chapitre 15 Bonnes pratiques en programmation Python
Remarque que ce style de nommage est appelé snake_case. Toutefois, il faut éviter d’utiliser les underscores en début et/ou en fin de
Nous avons appelé l’opération x, y, z = 1, 2, 3 affectation multiple pour signifier que l’on affectait des valeurs à nom de variable (par exemple : _var, var_, __var, __var__). On verra au chapitre 19 Avoir la classe avec les objets que ces
plusieurs variables en même temps. Toutefois, vous pourrez rencontrer aussi l’expression tuple unpacking que l’on pourrait underscores ont aussi une signification particulière.
traduire par « désempaquetage de tuple ». Cela signifie que l’on décompose le tuple initial 1, 2, 3 en 3 variables différentes.
Nous avions croisé l’importance de l’affectation multiple dans le chapitre 9 Fonctions lorsqu’une fonction renvoyait plu-
sieurs valeurs. 13.3.4 Tuples contenant des listes
1 >>> def ma_fonction (): Conseil : pour les débutants, vous pouvez passer cette rubrique.
2 ... return 3 , 14
3 ... On a vu que les tuples étaient non modifiables. Que se passe-t-il alors si on crée un tuple contenant des objets modifiables
4 >>> x , y = ma_fonction () comme des listes ? Examinons le code suivant :
5 >>> print (x , y )
6 3 14 1 >>> l1 = [1 , 2 , 3]
>>> t = ( l1 , " Plouf ")
La syntaxe x, y = ma_fonction() permet de récupérer les 2 valeurs renvoyées par la fonction et de les affecter à la
2
3 >>> t
volée dans 2 variables différentes. Cela évite l’opération laborieuse de récupérer d’abord le tuple, puis de créer les variables 4 ([1 , 2 , 3] , ' Plouf ')
5 >>> l1 [0] = -15
en utilisant l’indiçage : 6 >>> t [0]. append ( -632)
1 >>> resultat = ma_fonction () 7 >>> t
2 >>> resultat 8 ([ -15 , 2 , 3 , -632] , ' Plouf ')
3 (3 , 14)
4 >>> x = resultat [0] On voit que si on modifie un élément de la liste l1 en ligne 5 ou bien qu’on ajoute un élément à t[0] en ligne 6, Python
5 >>> y = resultat [1]
6 >>> print (x , y ) s’exécute et ne renvoie pas de message d’erreur. Or nous avions dit qu’un tuple était non modifiable. . . Comment cela-est il
7 3 14 possible ? Commençons d’abord par regarder comment les objets sont agencés avec Python Tutor.
La liste l1 pointe vers le même objet que l’élément du tuple d’indice 0. Comme pour la copie de liste (par exemple
liste1 = liste2), ceci est attendu car par défaut Python crée une copie par référence (cf. Chapitre 11 Plus sur les listes).
Conseil
Donc, qu’on raisonne en tant que premier élément du tuple ou bien en tant que liste l1, on pointe vers la même liste. Or,
Lorsqu’une fonction renvoie plusieurs valeurs sous forme de tuple, ce sera bien sûr la forme x, y = ma_fonction()
rappelez-vous, au début de ce chapitre nous avons expliqué que lorsqu’on modifiait un élément d’une liste, celle-ci gardait le
qui sera privilégiée.
même identifiant. C’est toujours le cas ici, même si celle-ci se trouve dans un tuple. Regardons cela :
1 >>> l1 = [1 , 2 , 3]
Quand une fonction renvoie plusieurs valeurs mais que l’on ne souhaite pas les utiliser toutes dans la suite du code, on 2 >>> t = ( l1 , " Plouf ")
>>> t
peut utiliser le nom de variable _ (caractère underscore) pour indiquer que certaines valeurs ne nous intéressent pas :
3
4 ([1 , 2 , 3] , ' Plouf ')
1 >>> def ma_fonction (): 5 >>> id ( l1 )
2 ... return 1 , 2 , 3 , 4 6 13997108198081 6
3 ... 7 >>> id ( t [0])
4 >>> x , _ , y , _ = ma_fonction () 8 13997108198081 6
5 >>> x
6 1 Nous confirmons ici le schéma de Python Tutor, c’est bien la même liste que l’on considère l1 ou t[0] puisqu’on a le
7 >>> y
8 3 même identifiant. Maintenant, on modifie cette liste via la variable l1 ou t[0] :
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 113 114 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
13.3. Tuples Chapitre 13. Containers, dictionnaires, tuples et sets Chapitre 13. Containers, dictionnaires, tuples et sets 13.4. Sets et frozensets
Les tuples t et t2 sont hachables car ils ne contiennent que des éléments hachables. Par contre, t3 ne l’est pas car un de
ses éléments est une liste.
Conseil
Mettre une ou des liste(s) dans un tuple a cette autre conséquence néfaste de le rendre non hachable. Ceci le rend inuti-
lisable comme clé de dictionnaire ou, on le verra ci-après, comme élément d’un set ou d’un frozenset. Donc, à nouveau, ne
mettez pas de listes dans vos tuples !
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 115 116 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
13.4. Sets et frozensets Chapitre 13. Containers, dictionnaires, tuples et sets Chapitre 13. Containers, dictionnaires, tuples et sets 13.4. Sets et frozensets
4 File " < stdin >" , line 1 , in < module > Notez qu’il existe des méthodes permettant de réaliser ces opérations d’union et d’intersection :
5 TypeError : 'set ' object is not subscriptable
6 >>> s [1] = 5 1 >>> s1 = {1 , 3 , 4 , 5}
7 Traceback ( most recent call last ): 2 >>> s2 = {0 , 1 , 2 , 3 , 5}
8 File " < stdin >" , line 1 , in < module > 3 >>> s1 . union ( s2 )
9 TypeError : 'set ' object does not support item assignment 4 {0 , 1 , 2 , 3 , 4 , 5}
5 >>> s1 . intersection ( s2 )
Par contre, les sets sont itérables : 6 {1 , 3 , 5}
>>> for element in s :
L’instruction s1.difference(s2) renvoie sous la forme d’un nouveau set les éléments de s1 qui ne sont pas dans s2. Et
1
2 ... print ( element )
3 ... vice-versa pour s2.difference(s1).
4 1
5 2 1 >>> s1 . difference ( s2 )
6 4 2 {4}
3 >>> s2 . difference ( s1 )
Les sets ne peuvent être modifiés que par des méthodes spécifiques. 4 {0 , 2}
1 >>> s = set ( range (5))
2 >>> s Enfin, deux autres méthodes sont très utiles :
3 {0 , 1 , 2 , 3 , 4} 1 >>> s1 = set ( range (10))
4 >>> s . add (4) 2 >>> s2 = set ( range (3 , 7))
5 >>> s 3 >>> s3 = set ( range (15 , 17))
6 {0 , 1 , 2 , 3 , 4} 4 >>> s1
7 >>> s . add (472) 5 {0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9}
8 >>> s 6 >>> s2
9 {0 , 1 , 2 , 3 , 4 , 472} 7 {3 , 4 , 5 , 6}
10 >>> s . discard (0) 8 >>> s3
11 >>> s 9 {16 , 15}
12 {1 , 2 , 3 , 4 , 472} 10 >>> s2 . issubset ( s1 )
11 True
La méthode .add() ajoute au set l’élément passé en argument. Toutefois, si l’élément est déjà présent dans le set, il 12 >>> s3 . isdisjoint ( s1 )
n’est pas ajouté puisqu’on a au plus une copie de chaque élément. La méthode .discard() retire du set l’élément passé en 13 True
argument. Si l’élément n’est pas présent dans le set, il ne se passe rien, le set reste intact. Comme les sets ne sont pas ordonnés La méthode .issubset() indique si un set est inclus dans un autre set. La méthode isdisjoint() indique si un set est
ni indexables, il n’y a pas de méthode pour insérer un élément à une position précise contrairement aux listes. Dernier point disjoint d’un autre set, c’est-à-dire, s’ils n’ont aucun élément en commun indiquant que leur intersection est nulle.
sur ces méthodes, elles modifient le set sur place (in place en anglais) et ne renvoient rien à l’instar des méthodes des listes Il existe de nombreuses autres méthodes que nous n’abordons pas ici mais qui peuvent être consultées sur la documentation
(.append(), .remove(), etc.). officielle de Python 4 .
Enfin, les sets ne supportent pas les opérateurs + et *.
13.4.3 Frozensets
13.4.2 Utilité
Les frozensets sont des sets non modifiables et hachables. Ainsi, un set peut contenir des frozensets mais pas l’inverse. A
Les containers de type set sont très utiles pour rechercher les éléments uniques d’une suite d’éléments. Cela revient à quoi servent-ils ? Comme la différence entre tuple et liste, l’immutabilité des frozensets donne l’assurance de ne pas pouvoir
éliminer tous les doublons. Par exemple : les modifier par erreur. Pour créer un frozenset on utilise la fonction interne frozenset() qui prend en argument un objet
1 >>> import random itérable et le convertit (opération de casting) :
2 >>> liste = [ random . randint (0 , 9) for i in range (10)]
3 >>> liste 1 >>> f1 = frozenset ([3 , 3 , 5 , 1 , 3 , 4 , 1 , 1 , 4 , 4])
4 [7 , 9 , 6 , 6 , 7 , 3 , 8 , 5 , 6 , 7] 2 >>> f2 = frozenset ([3 , 0 , 5 , 3 , 3 , 1 , 1 , 1 , 2 , 2])
5 >>> set ( liste ) 3 >>> f1
6 {3 , 5 , 6 , 7 , 8 , 9} 4 frozenset ({1 , 3 , 4 , 5})
5 >>> f2
On peut bien sûr transformer dans l’autre sens un set en liste. Cela permet par exemple d’éliminer les doublons de la liste 6 frozenset ({0 , 1 , 2 , 3 , 5})
7 >>> f1 . add (5)
initiale tout en récupérant une liste à la fin : 8 Traceback ( most recent call last ):
9 File " < stdin >" , line 1 , in < module >
1 >>> list ( set ([7 , 9 , 6 , 6 , 7 , 3 , 8 , 5 , 6 , 7])) 10 AttributeErro r : ' frozenset ' object has no attribute 'add '
2 [3 , 5 , 6 , 7 , 8 , 9] 11 >>> f1 . union ( f2 )
12 frozenset ({0 , 1 , 2 , 3 , 4 , 5})
On peut faire des choses très puissantes. Par exemple, un compteur de lettres en combinaison avec une liste de compré- 13 >>> f1 . intersection ( f2 )
hension, le tout en une ligne ! 14 frozenset ({1 , 3 , 5})
>>> seq = " a t c t c g a t c g a t c g c g c t a g c t a g c t c g c c a t a c g t a c g a c t a c g t "
1
2 >>> set ( seq )
Les frozensets ne possèdent bien sûr pas les méthodes de modification des sets (.add(), .discard(), etc.) puisqu’ils
3 { 'c ' , 'g ' , 't ' , 'a '} sont non modifiables. Par contre, ils possèdent toutes les méthodes de comparaisons de sets (.union(), .intersection(),
4 >>> [( base , seq . count ( base )) for base in set ( seq )] etc.).
5 [( 'c ' , 15) , ( 'g ' , 10) , ( 't ' , 11) , ( 'a ' , 10)]
Les sets permettent aussi l’évaluation d’union ou d’intersection mathématiques en conjonction avec les opérateurs respec- Conseil
tivement | et & : Pour aller plus loin sur les sets et les frozensets, voici deux articles sur les sites programiz 5 et towardsdatascience 6 .
1 >>> liste_1 = [3 , 3 , 5 , 1 , 3 , 4 , 1 , 1 , 4 , 4]
2 >>> liste_2 = [3 , 0 , 5 , 3 , 3 , 1 , 1 , 1 , 2 , 2]
3 >>> set ( liste_1 ) | set ( liste_2 )
4 {0 , 1 , 2 , 3 , 4 , 5} 4. https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset
5 >>> set ( liste_1 ) & set ( liste_2 ) 5. https://www.programiz.com/python-programming/set
6 {1 , 3 , 5} 6. https://towardsdatascience.com/python-sets-and-set-theory-2ace093d1607
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 117 118 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
13.6. Dictionnaires et sets de compréhension Chapitre 13. Containers, dictionnaires, tuples et sets Chapitre 13. Containers, dictionnaires, tuples et sets 13.7. Module collections
13.5 Récapitulation des propriétés des containers 7 >>> animaux = ((" singe " , 3) , (" girafe " , 1) , (" rhinoc é ros " , 1) , (" gazelle " , 4))
8 >>> { ani : nb for ani , nb in animaux }
9 { ' singe ': 3 , ' girafe ': 1 , ' rhinoc é ros ': 1 , ' gazelle ': 4}
Après ce tour d’horizon des différents containers, voici un tableau récapitulant leurs propriétés.
Avec un dictionnaire de compréhension, on peut rapidement compter le nombre de chaque base dans une séquence
13.5.1 Objets séquentiels d’ADN :
1 >>> seq = " a t c t c g a t c g a t c g c g c t a g c t a g c t c g c c a t a c g t a c g a c t a c g t "
2 >>> { base : seq . count ( base ) for base in set ( seq )}
Container test d’appartenance et fonction len() itérable ordonné indexable modifiable hachable 3 { 'a ': 10 , 'g ': 10 , 't ': 11 , 'c ': 15}
liste oui oui oui oui oui non De manière générale, tout objet sur lequel on peut faire une double itération du type for var1, var2 in obj est
chaîne de caractères oui oui oui oui non oui utilisable pour créer un dictionnaire de compréhension. Si vous souhaitez aller plus loin, vous pouvez consulter cet article 7
range oui oui oui oui non oui sur le site Datacamp.
tuple oui oui oui oui non oui∗ Il est également possible de générer des sets de compréhension sur le même modèle que les listes de compréhension :
1 >>> { i for i in range (10)}
∗ 2 {0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9}
s’il ne contient que des objets hachables 3 >>> { i **2 for i in range (10)}
4 {0 , 1 , 64 , 4 , 36 , 9 , 16 , 49 , 81 , 25}
5 >>>
13.5.2 Objects de mapping 6 >>> animaux = ((" singe " , 3) , (" girafe " , 1) , (" rhinoc é ros " , 1) , (" gazelle " , 4))
7 >>> { ani for ani , _ in animaux }
8 { ' rhinoc é ros ' , ' gazelle ' , ' singe ' , ' girafe '}
Container test d’appartenance et fonction len() itérable ordonné indexable modifiable hachable
dictionnaire oui oui sur oui∗ non oui non
les clés 13.7 Module collections
Conseil : pour les débutants, vous pouvez passer cette rubrique.
∗ à partir de Python 3.7 uniquement Le module collections 8 contient d’autres types de containers qui peuvent se révéler utiles, c’est une véritable mine d’or !
Nous n’aborderons pas tous ces objets ici, mais nous pouvons citer tout de même certains d’entre eux si vous souhaitez aller
13.5.3 Objets sets un peu plus loin :
— les dictionnaires ordonnés 9 qui se comportent comme les dictionnaires classiques mais qui sont ordonnés ;
— les defaultdicts 10 permettant de générer des valeurs par défaut quand on demande une clé qui n’existe pas (cela évite
Container test d’appartenance et fonction len() itérable ordonné indexable modifiable hachable que Python génère une erreur) ;
sets oui oui non non oui non — les compteurs 11 dont un exemple est montré ci-dessous ;
frozensets oui oui non non non oui — les namedtuples 12 que nous évoquerons au chapitre 19 Avoir la classe avec les objets.
L’objet collection.Counter() est particulièrement intéressant et simple à utiliser. Il crée des compteurs à partir d’ob-
jets itérables, par exemple :
13.5.4 Types de base 1 >>> import collections
2 >>> compo_seq = collections . Counter (" a a t c t c c g a t c g a t c g a t c g a t g a t c ")
Il est aussi intéressant de comparer ces propriétés avec celles des types numériques de base qui ne sont pas des containers. 3 >>> compo_seq
4 Counter ({ 'a ': 7 , 't ': 7 , 'c ': 7 , 'g ': 5})
5 >>> type ( compo_seq )
Objet 6 < class ' collections . Counter ' >
numérique test d’appartenance et fonction len() itérable ordonné indexable modifiable hachable 7 >>> compo_seq [" a "]
8 7
entier non non non non non oui 9 >>> compo_seq [" n "]
10 0
float non non non non non oui
booléen non non non non non oui Dans cet exemple, Python a automatiquement compté chaque caractère a, t, g et c de la chaîne de caractères passée en
argument. Cela crée un objet de type Counter qui se comporte ensuite comme un dictionnaire, à une exception près : si on
appelle une clé qui n’existe pas dans l’itérable initiale (comme le n ci-dessus) la valeur renvoyée est 0.
13.6 Dictionnaires et sets de compréhension
13.8 Exercices
Conseil : pour les débutants, vous pouvez passer cette rubrique.
Nous avons vu au chapitre 11 Plus sur les listes les listes de compréhension. Il est également possible de générer des Conseil : pour ces exercices, créez des scripts puis exécutez-les dans un shell.
dictionnaires de compréhension :
7. https://www.datacamp.com/community/tutorials/python-dictionary-comprehension
1 >>> dico = {" a ": 10 , " g ": 10 , " t ": 11 , " c ": 15}
8. https://docs.python.org/fr/3/library/collections.html
2 >>> dico . items ()
3 dict_items ([( ' a ' , 10) , ( 'g ' , 10) , ( 't ' , 11) , ( 'c ' , 15)]) 9. https://docs.python.org/fr/3/library/collections.html#collections.OrderedDict
4 >>> { key : val *2 for key , val in dico . items ()} 10. https://docs.python.org/fr/3/library/collections.html#collections.defaultdict
5 { 'a ': 20 , 'g ': 20 , 't ': 22 , 'c ': 30} 11. https://docs.python.org/fr/3/library/collections.html#collections.Counter
6 >>> 12. https://docs.python.org/fr/3/library/collections.html#collections.namedtuple
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 119 120 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
13.8. Exercices Chapitre 13. Containers, dictionnaires, tuples et sets Chapitre 13. Containers, dictionnaires, tuples et sets 13.8. Exercices
13.8.1 Composition en acides aminés 13.8.5 Atomes carbone alpha d’un fichier PDB
En utilisant un dictionnaire, déterminez le nombre d’occurrences de chaque acide aminé dans la séquence AGWPSGGASAGLAILWGASAIMPGALW. Téléchargez le fichier 1bta.pdb 16 qui correspond à la structure tridimensionnelle de la protéine barstar 17 sur le site de la
Le dictionnaire ne doit contenir que les acides aminés présents dans la séquence. Protein Data Bank (PDB).
Créez la fonction trouve_calpha() qui prend en argument le nom d’un fichier PDB (sous la forme d’une chaîne de
caractères), qui sélectionne uniquement les lignes contenant des carbones alpha et qui les renvoie sous la forme d’une liste de
13.8.2 Mots de 2 et 3 lettres dans une séquence d’ADN dictionnaires. Chaque dictionnaire contient quatre clés :
— le numéro du résidu (resid) avec une valeur entière,
Créez une fonction compte_mots_2_lettres() qui prend comme argument une séquence sous la forme d’une chaîne de — la coordonnée atomique x (x) avec une valeur float,
caractères et qui renvoie tous les mots de 2 lettres qui existent dans la séquence sous la forme d’un dictionnaire. Par exemple — la coordonnée atomique y (y) avec une valeur float,
pour la séquence ACCTAGCCCTA, le dictionnaire renvoyée serait : {'AC': 1, 'CC': 3, 'CT': 2, 'TA': 2, 'AG': 1, — la coordonnée atomique z (z) avec une valeur float.
'GC': 1} Utilisez la fonction trouve_calpha() pour afficher à l’écran le nombre total de carbones alpha de la barstar ainsi que les
Créez une nouvelle fonction compte_mots_3_lettres() qui a un comportement similaire à compte_mots_2_lettres() coordonnées atomiques des carbones alpha des deux premiers résidus (acides aminés).
mais avec des mots de 3 lettres. Conseil : vous trouverez des explications sur le format PDB et des exemples de code pour lire ce type de fichier en Python
Utilisez ces fonctions pour affichez les mots de 2 et 3 lettres et leurs occurrences trouvés dans la séquence d’ADN : dans l’annexe A Quelques formats de données rencontrés en biologie.
ACCTAGCCATGTAGAATCGCCTAGGCTTTAGCTAGCTCTAGCTAGCTG
Voici un exemple de sortie attendue : 13.8.6 Barycentre d’une protéine (exercice +++)
1 Mots de 2 lettres Téléchargez le fichier 1bta.pdb 18 qui correspond à la structure tridimensionnelle de la protéine barstar 19 sur le site de la
2 AC : 1
3 CC : 3 Protein Data Bank (PDB).
4 CT : 8
5 [...]
Un carbone alpha est présent dans chaque résidu (acide aminé) d’une protéine. On peut obtenir une bonne approximation
6 Mots de 3 lettres du barycentre d’une protéine en calculant le barycentre de ses carbones alpha.
7 ACC : 1
8 CCT : 2 Le barycentre G de coordonnées (Gx , Gy , Gz ) est obtenu à partir des n carbones alpha (CA) de coordonnées (CAx , CAy ,
9 CTA : 5 CAz ) avec :
10 [...]
1 n
Gx = ∑ CAi,x
n i=1
13.8.3 Mots de 2 lettres dans la séquence du chromosome I de Saccharomyces cerevisiae 1 n
Gy = ∑ CAi,y
n i=1
Créez une fonction lit_fasta() qui prend comme argument le nom d’un fichier FASTA sous la forme d’une chaîne de
caractères, lit la séquence dans le fichier FASTA et la renvoie sous la forme d’une chaîne de caractères. N’hésitez pas à vous 1 n
inspirer d’un exercice similaire du chapitre 10 Plus sur les chaînes de caractères. Gz = ∑ CAi,z
n i=1
Utilisez cette fonction et la fonction compte_mots_2_lettres() de l’exercice précédent pour extraire les mots de 2
lettres et leurs occurrences dans la séquence du chromosome I de la levure du boulanger Saccharomyces cerevisiae (fichier Créez une fonction calcule_barycentre() qui prend comme argument une liste de dictionnaires dont les clés (resid,
NC_001133.fna 13 ). x, y et z) sont celles de l’exercice précédent et qui renvoie les coordonnées du barycentre sous la forme d’une liste de floats.
Le génome complet est fourni au format FASTA. Vous trouverez des explications sur ce format et des exemples de code Utilisez la fonction trouve_calpha() de l’exercice précédent et la fonction
dans l’annexe A Quelques formats de données rencontrés en biologie. calcule_barycentre()pour afficher, avec deux chiffres significatifs, les coordonnées du barycentre des carbones alpha de
la barstar.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 121 122 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
Chapitre 14. Création de modules 14.3. Utilisation de son propre module
Chapitre 14 Remarque
Avec Mac OS X et Linux, il faut taper la commande suivante depuis un shell Bash pour modifier la variable d’environne-
ment PYTHONPATH :
export PYTHONPATH=$PYTHONPATH:/chemin/vers/mon/super/module
Création de modules Avec Windows, mais depuis un shell PowerShell, il faut taper la commande suivante :
$env:PYTHONPATH += ";C:\chemin\vers\mon\super\module"
Une fois cette manipulation effectuée, vous pouvez contrôler que le chemin vers le répertoire contenant vos modules a
bien été ajouté à la variable d’environnement PYTHONPATH :
— sous Mac OS X et Linux : echo $PYTHONPATH
— sous Windows : echo $env:PYTHONPATH
14.1 Pourquoi créer ses propres modules ?
Dans le chapitre 8 Modules, nous avons découvert quelques modules existants dans Python comme random, math, etc. Le chargement du module se fait avec la commande import message. Notez que le fichier est bien enregistré avec une
Nous avons vu par ailleurs dans les chapitres 9 Fonctions et 12 Plus sur les fonctions que les fonctions sont utiles pour extension .py et pourtant on ne la précise pas lorsqu’on importe le module. Ensuite, on peut utiliser les fonctions comme avec
réutiliser une fraction de code plusieurs fois au sein d’un même programme sans avoir à dupliquer ce code. On peut imaginer un module classique.
qu’une fonction bien écrite pourrait être judicieusement réutilisée dans un autre programme Python. C’est justement l’intérêt 1 >>> import message
2 >>> message . hello (" Joe ")
de créer un module. On y met un ensemble de fonctions que l’on peut être amené à utiliser souvent. En général, les modules 3 ' Hello Joe '
sont regroupés autour d’un thème précis. Par exemple, on pourrait concevoir un module d’analyse de séquences biologiques 4 >>> message . ciao (" Bill ")
5 ' Ciao Bill '
ou encore de gestion de fichiers PDB. 6 >>> message . bonjour (" Monsieur ")
7 ' Bonjour Monsieur '
8 >>> message . DATE
9 16092008
1. https://docs.python.org/fr/3/glossary.html
123 124 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
14.5. Visibilité des fonctions dans un module Chapitre 14. Création de modules Chapitre 14. Création de modules 14.7. Exercice
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 125 126 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
Chapitre 15. Bonnes pratiques en programmation Python 15.1. De la bonne syntaxe avec la PEP 8
Attention
Afin de toujours utiliser cette règle des 4 espaces pour l’indentation, il est essentiel de régler correctement votre éditeur
de texte. Consultez pour cela l’annexe Installation de Python disponible en ligne 3 . Avant d’écrire la moindre ligne de code,
faites en sorte que lorsque vous pressez la touche tabulation, cela ajoute 4 espaces (et non pas un caractère tabulation).
Chapitre 15
15.1.2 Importation des modules
Comme on l’a vu au chapitre 8 Modules, le chargement d’un module se fait avec l’instruction import module plutôt
Bonnes pratiques en programmation Python qu’avec from module import *.
Si on souhaite ensuite utiliser une fonction d’un module, la première syntaxe conduit à module.fonction() ce qui rend
explicite la provenance de la fonction. Avec la seconde syntaxe, il faudrait écrire fonction() ce qui peut :
— mener à un conflit si une de vos fonctions a le même nom ;
— rendre difficile la recherche de documentation si on ne sait pas d’où vient la fonction, notamment si plusieurs modules
Comme vous l’avez constaté dans tous les chapitres précédents, la syntaxe de Python est très permissive. Afin d’unifor- sont chargés avec l’instruction
miser l’écriture de code en Python, la communauté des développeurs Python recommande un certain nombre de règles afin from module import *
qu’un code soit lisible. Lisible par quelqu’un d’autre, mais également, et surtout, par soi-même. Essayez de relire un code que Par ailleurs, la première syntaxe définit un « espace de noms » (voir chapitre 19 Avoir la classe avec les objets) spécifique
vous avez écrit « rapidement » il y a un 1 mois, 6 mois ou un an. Si le code ne fait que quelques lignes, il se peut que vous au module.
vous y retrouviez, mais s’il fait plusieurs dizaines voire centaines de lignes, vous serez perdus. Dans un script Python, on importe en général un module par ligne. D’abord les modules internes (classés par ordre
Dans ce contexte, le créateur de Python, Guido van Rossum, part d’un constat simple : « code is read much more often than alphabétique), c’est-à-dire les modules de base de Python, puis les modules externes (ceux que vous avez installés en plus).
it is written » (« le code est plus souvent lu qu’écrit »). Avec l’expérience, vous vous rendrez compte que cela est parfaitement Si le nom du module est trop long, on peut utiliser un alias. L’instruction from est tolérée si vous n’importez que quelques
vrai. Alors plus de temps à perdre, voyons en quoi consistent ces bonnes pratiques. fonctions clairement identifiées.
Plusieurs choses sont nécessaires pour écrire un code lisible : la syntaxe, l’organisation du code, le découpage en fonctions En résumé :
(et possiblement en classes que nous verrons dans le chapitre 19 Avoir la classe avec les objets), mais souvent, aussi, le bon 1 import module_ i n t e r ne _ 1
sens. Pour cela, les « PEP » peuvent nous aider. 2 import module_ i n t e r ne _ 2
3 from module_in t e r ne _ 3 import fonction_sp é cifique
4 from module_in t e r ne _ 4 import constante_1 , fonction_1 , fonction_2
Définition 5
6 import module_ e x t e r ne _ 1
Afin d’améliorer le langage Python, la communauté qui développe Python publie régulièrement des Python Enhance- 7 import module_ e x t e r ne _ 2
import m o d u l e _ e x t e r n e _ 3 _ q u i _ a _ u n _ n o m _ l o n g as mod3
ment Proposal 1 (PEP), suivi d’un numéro. Il s’agit de propositions concrètes pour améliorer le code, ajouter de nouvelles 8
fonctionnalités, mais aussi des recommandations sur la manière d’utiliser Python, bien écrire du code, etc.
127 128 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
15.1. De la bonne syntaxe avec la PEP 8 Chapitre 15. Bonnes pratiques en programmation Python Chapitre 15. Bonnes pratiques en programmation Python 15.1. De la bonne syntaxe avec la PEP 8
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 129 130 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
15.2. Les docstrings et la PEP 257 Chapitre 15. Bonnes pratiques en programmation Python Chapitre 15. Bonnes pratiques en programmation Python 15.2. Les docstrings et la PEP 257
15.1.7 Commentaires La PEP 257 recommande d’écrire des docstrings avec des triples doubles guillemets, c’est-à-dire
"""Ceci est une docstring recommandée."""
Les commentaires débutent toujours par le symbole # suivi d’un espace. Ils donnent des explications claires sur l’utilité
mais pas
du code et doivent être synchronisés avec le code, c’est-à-dire que si le code est modifié, les commentaires doivent l’être aussi
(le cas échéant). '''Ceci n'est pas une docstring recommandée.'''.
Les commentaires sont sur le même niveau d’indentation que le code qu’ils commentent. Les commentaires sont constitués
de phrases complètes, avec une majuscule au début (sauf si le premier mot est une variable qui s’écrit sans majuscule) et un
Comme indiqué dans le chapitre 14 Création de modules, n’oubliez pas que les docstrings sont destinées aux utilisateurs
point à la fin.
des modules, fonctions, méthodes et classes que vous avez développés. Les éléments essentiels pour les fonctions et les
La PEP 8 recommande très fortement d’écrire les commentaires en anglais, sauf si vous êtes à 120% sûr que votre code ne
méthodes sont :
sera lu que par des francophones. Dans la mesure où vous allez souvent développer des programmes scientifiques, nous vous
conseillons d’écrire vos commentaires en anglais. 1. ce que fait la fonction ou la méthode,
Soyez également cohérent entre la langue utilisée pour les commentaires et la langue utilisée pour nommer les variables.
2. ce qu’elle prend en argument,
Pour un programme scientifique, les commentaires et les noms de variables sont en anglais. Ainsi ma_liste deviendra
my_list et ma_fonction deviendra my_function (par exemple). 3. ce qu’elle renvoie.
Les commentaires qui suivent le code sur la même ligne sont à éviter le plus possible et doivent être séparés du code par
au moins deux espaces : Pour les modules et les classes, on ajoute également des informations générales sur leur fonctionnement.
Pour autant, la PEP 257 ne dit pas explicitement comment organiser les docstrings pour les fonctions et les méthodes.
1 x = x + 1 # My wonderful comment .
Pour répondre à ce besoin, deux solutions ont émergées :
— La solution Google avec le Google Style Python Docstrings 5 .
Remarque — La solution NumPy avec le NumPy Style Python Docstrings 6 . NumPy qui est un module complémentaire à Python, très
Nous terminerons par une remarque qui concerne la syntaxe, mais qui n’est pas incluse dans la PEP 8. On nous pose utilisé en analyse de données et dont on parlera dans le chapitre 17 Quelques modules d’intérêt en bioinformatique.
souvent la question du type de guillemets à utiliser pour déclarer une chaîne de caractères. Simples ou doubles ? On illustre ici la solution NumPy pour des raisons de goût personnel. Sentez-vous libre d’aller explorer la proposition de
1 >>> var_1 = " Ma cha î ne de caract è res " Google. Voici un exemple très simple :
2 >>> var_1
3 ' Ma cha î ne de caract è res ' 1 def mul tip lie_ n o m b r e s ( nombre1 , nombre2 ):
4 >>> var_2 = ' Ma cha î ne de caract è res ' 2 """ Multiplicati on de deux nombres entiers .
5 >>> var_2 3
6 ' Ma cha î ne de caract è res ' 4 Cette fonction ne sert pas à grand chose .
7 >>> var_1 == var_2 5
8 True 6 Parameters
7 ----------
Vous constatez dans l’exemple ci-dessus que pour Python, c’est exactement la même chose. Et à notre connaissance, il 8 nombre1 : int
9 Le premier nombre entier .
n’existe pas de recommandation officielle sur le sujet. 10 nombre2 : int
11 Le second nombre entier .
Nous vous conseillons cependant d’utiliser les guillemets doubles car ceux-ci sont, de notre point de vue, plus lisibles. 12
13 Avec une description plus longue .
14 Sur plusieurs lignes .
15
16 Returns
17 -------
int
15.2 Les docstrings et la PEP 257 18
19 Le produit des deux nombres .
20 """
21 return nombre1 * nombre2
Les docstrings, que l’on pourrait traduire par « chaînes de documentation » en français, sont un élément essentiel de nos
programmes Python comme on l’a vu au chapitre 14 Création de modules. À nouveau, les développeurs de Python ont émis Lignes 6 et 7. La section Parameters précise les paramètres de la fonction. Les tirets sur la ligne 7 permettent de souligner
des recommandations dans la PEP 8 et plus exhaustivement dans la PEP 257 4 sur la manière de rédiger correctement les le nom de la section et donc de la rendre visible.
docstrings. En voici un résumé succinct. Lignes 8 et 9. On indique le nom et le type du paramètre séparés par le caractère deux-points. Le type n’est pas obligatoire.
De manière générale, écrivez des docstrings pour les modules, les fonctions, les classes et les méthodes. Lorsque l’expli- En dessous, on indique une description du paramètre en question. La description est indentée.
cation est courte et compacte comme dans certaines fonctions ou méthodes simples, utilisez des docstrings d’une ligne : Lignes 10 à 14. Même chose pour le second paramètre. La description du paramètre peut s’étaler sur plusieurs lignes.
""" Docstring simple d ' une ligne se finissant par un point ."""
1
Lignes 16 et 17. La section Returns indique ce qui est renvoyé par la fonction (le cas échéant).
Lorsque vous avez besoin de décrire plus en détail un module, une fonction, une classe ou une méthode, utilisez une Lignes 18 et 19. La mention du type renvoyé est obligatoire. En dessous, on indique une description de ce qui est renvoyé
docstring sur plusieurs lignes. par la fonction. Cette description est aussi indentée.
1 """ Docstring de plusieurs lignes , la premi è re ligne est un r é sum é .
2
3 Apr è s avoir saut é une ligne , on d é crit les d é tails de cette docstring . Attention
4 blablabla L’être humain a une fâcheuse tendance à la procrastination (le fameux « Bah je le ferai demain. . . ») et écrire de la docu-
5 blablabla
6 blublublu mentation peut être un sérieux motif de procrastination. Soyez vigilant sur ce point, et rédigez vos docstrings au moment où
7 bliblibli vous écrivez vos modules, fonctions, classes ou méthodes. Passer une journée (voire plusieurs) à écrire les docstrings d’un
8 On termine la docstring avec les triples guillemets sur la ligne suivante .
9 """ gros projet est particulièrement pénible. Croyez-nous !
Remarque
5. https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_google.html
4. https://www.python.org/dev/peps/pep-0257/ 6. https://sphinxcontrib-napoleon.readthedocs.io/en/latest/example_numpy.html
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 131 132 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
15.3. Outils de contrôle qualité du code Chapitre 15. Bonnes pratiques en programmation Python Chapitre 15. Bonnes pratiques en programmation Python 15.4. Organisation du code
15.3 Outils de contrôle qualité du code Ligne 4. Il y un espace de trop après le second argument nombre2 dans la définition de la fonction Multiplie_nombres()
à la ligne 6 (colonne 38) du script.
Pour évaluer la qualité d’un code Python, c’est-à-dire sa conformité avec les recommandations de la PEP 8 et de la PEP Ligne 5. Il manque un espace après l’opérateur * à la ligne 26 (colonne 21) du script.
257, on peut utiliser des sites internet ou des outils dédiés. Ligne 6. Il y a un espace de trop entre print et ( à la ligne 31 (colonne 10) du script.
Le site pep8online 7 , par exemple, est très simple d’utilisation. On copie / colle le code à évaluer puis on clique sur le Remarquez que curieusement, pycodestyle n’a pas détecté que le nom de la fonction Multiplie_nombres() ne res-
bouton Check code. pecte pas la convention de nommage.
Les outils pycodestyle, pydocstyle et pylint doivent par contre être installés sur votre machine. Avec la distribution Ensuite, l’outil pydocstyle va vérifier la conformité avec la PEP 257 et s’intéresser particulièrement aux docstrings :
Miniconda, cette étape d’installation se résume à une ligne de commande :
1 $ pydocstyle s c r i p t _ q u a l i t y _ n o t _ o k . py
1 $ conda install -c conda - forge pycodestyle pydocstyle pylint 2 s c r i p t _ q u a l i t y _ n o t _ o k . py :1 at module level :
3 D200 : One - line docstring should fit on one line with quotes ( found 2)
4 s c r i p t _ q u a l i t y _ n o t _ o k . py :7 in public function ` Multiplie_nombres `:
5 D205 : 1 blank line required between summary line and description ( found 0)
Définition 6 s c r i p t _ q u a l i t y _ n o t _ o k . py :7 in public function ` Multiplie_nombres `:
Les outils pycodestyle, pydocstyle et pylint sont des linters, c’est-à-dire des programmes qui vont chercher les 7 D400 : First line should end with a period ( not 's ')
sources potentielles d’erreurs dans un code informatique. Ces erreurs peuvent être des erreurs de style (PEP 8 et 257) ou des Lignes 2 et 3. pydocstyle indique que la docstring à la ligne 1 du script est sur deux lignes alors qu’elle devrait être sur
erreurs logiques (manipulation d’une variable, chargement de module). une seule ligne.
Lignes 4 et 5. Dans la docstring de la fonction Multiplie_nombres() (ligne 7 du script), il manque une ligne vide entre
Voici le contenu du script script_quality_not_ok.py 8 que nous allons analyser par la suite : la ligne résumé et la description plus complète.
Lignes 6 et 7. Dans la docstring de la fonction Multiplie_nombres() (ligne 7 du script), il manque un point à la fin de
1 """ Un script de multiplication .
2 """ la première ligne.
3
4 import os Les outils pycodestyle et pydocstyle vont simplement vérifier la conformité aux PEP 8 et 257. L’outil pylint va lui
5 aussi vérifier une partie de ces règles mais il va également essayer de comprendre le contexte du code et proposer des éléments
6 def Mul tip lie_ no m b re s ( nombre1 , nombre2 ):
7 """ Multiplicati on de deux nombres entiers d’amélioration. Par exemple :
8 Cette fonction ne sert pas à grand chose .
9
1 $ pylint s c r i p t _ q u a l i t y _ n o t _ o k . py
10 Parameters 2 ************* Module s c r i p t _ q u a l i t y _ n o t _ o k
11 ---------- 3 s c r i p t _ q u a l i t y _ n o t _ o k . py :6:29: C0326 : Exactly one space required after comma
12 nombre1 : int 4 def Mul tip lie_ n o m b r e s ( nombre1 , nombre2 ):
13 Le premier nombre entier . 5 ^ ( bad - whitespace )
14 nombre2 : int 6 s c r i p t _ q u a l i t y _ n o t _ o k . py :6:38: C0326 : No space allowed before bracket
15 Le second nombre entier . 7 def Mul tip lie_ n o m b r e s ( nombre1 , nombre2 ):
16 8 ^ ( bad - whitespace )
17 Avec une description plus longue . 9 s c r i p t _ q u a l i t y _ n o t _ o k . py :31:10: C0326 : No space allowed before bracket
18 Sur plusieurs lignes . 10 print (( f "4 x 5 = { M ul ti p l i e _ n o m b r e s (4 , 5)}")
19
Returns 11 ^ ( bad - whitespace )
20
21 ------- 12 s c r i p t _ q u a l i t y _ n o t _ o k . py :6:0: C0103 : Function name " M u l t i p l i e _n om br e s "
22 int 13 doesn ' t conform to snake_case naming style ( invalid - name )
23 Le produit des deux nombres . 14 s c r i p t _ q u a l i t y _ n o t _ o k . py :4:0: W0611 : Unused import os ( unused - import )
24 15
25 """ 16 -----------------------------------
26 return nombre1 * nombre2 17 Your code has been rated at 0.00/10
27
28
29 if __name__ == " __main__ ": Lignes 3 à 5. pylint indique qu’il manque un espace entre les paramètres de la fonction Multiplie_nombres() (ligne
30 print ( f "2 x 3 = { Mul t ipl ie_ n om bre s (2 , 3)}") 6 et colonne 29 du script). La ligne du script qui pose problème est affichée, ce qui est pratique.
31 print ( f "4 x 5 = { Mu lti pli e _no mbr es (4 , 5)}") Lignes 6 à 8. pylint identifie un espace de trop après le second paramètre de la fonction Multiplie_nombres().
Ce script est d’ailleurs parfaitement fonctionnel : Ligne 9 à 11. Il y a un espace de trop entre print et (.
1 $ python scr ip t _ qua li t y _o k . py
Lignes 12 et 13. Le nom de la fonction Multiplie_nombres() ne respecte pas la convention PEP 8. La fonction devrait
2 2 x 3 = 6 s’appeler multiplie_nombres().
4 x 5 = 20
3
Ligne 14. Le module os est chargé mais pas utilisé (ligne 4 du script).
On va tout d’abord vérifier la conformité avec la PEP 8 avec l’outil pycodestyle : Ligne 17. pylint produit également une note sur 10. Ne soyez pas surpris si cette note est très basse (voire négative) la
1 $ pycodestyle s c r i p t _ q u a l i t y _ n o t _ o k . py première fois que vous analysez votre script avec pylint. Cet outil fournit de nombreuses suggestions d’amélioration et la
2 s c r i p t _ q u a l i t y _ n o t _ o k . py :6:1: E302 expected 2 blank lines , found 1 note attribuée à votre script devrait rapidement augmenter. Pour autant, la note de 10 est parfois difficile à obtenir. Ne soyez
3 s c r i p t _ q u a l i t y _ n o t _ o k . py :6:30: E231 missing whitespace after ','
4 s c r i p t _ q u a l i t y _ n o t _ o k . py :6:38: E202 whitespace before ') ' pas trop exigeant.
5 s c r i p t _ q u a l i t y _ n o t _ o k . py :26:21: E225 missing whitespace around operator Une version améliorée du script précédent est disponible en ligne 9 .
6 s c r i p t _ q u a l i t y _ n o t _ o k . py :31:10: E211 whitespace before '( '
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 133 134 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
15.4. Organisation du code Chapitre 15. Bonnes pratiques en programmation Python Chapitre 15. Bonnes pratiques en programmation Python 15.5. Conseils sur la conception d’un script
1 """ Docstring d ' une ligne d é crivant bri è vement ce que fait le programme . métadonnées ne sont pas obligatoires, mais elles sont utiles lorsque le code est distribué à la communauté.
2
3 Usage : Lignes 17 à 20. Importation des modules. D’abord les modules internes à Python (fournis en standard), puis les modules
4 ====== externes (ceux qu’il faut installer en plus), un module par ligne.
5 python n o m _ d e _ c e _ s u p e r _ s c r i p t . py argument1 argument2
6 Lignes 22 et 23. Définition des constantes. Le nom des constantes est en majuscule.
7 argument1 : un entier signifiant un truc Ligne 26. Définition d’une classe. On a laissé deux lignes vides avant.
8 argument2 : une cha î ne de caract è res d é crivant un bidule
9 """ Lignes 27 à 32. Docstring décrivant la classe.
10
11 __authors__ = (" Johny B Good " , " Hubert de la P â te Feuillet é e ")
Lignes 33, 42 et 46. Avant chaque méthode de la classe, on laisse une ligne vide.
12 __contact__ = (" johny@bgood . us " , " hub@pate . feuilletee . fr ") Lignes 58 à 72. Après les classes, on met les fonctions « classiques ». Avant chaque fonction, on laisse deux lignes vides.
13 __copyright__ = " MIT " Lignes 75 à 77. On écrit le programme principal. Le test ligne 76 n’est vrai que si le script est utilisé en tant que programme.
14 __date__ = "2030 -01 -01"
15 __version__ = "1.2.3" Les lignes suivantes ne sont donc pas exécutées si le script est chargé comme un module.
16
17 import module_interne
18 import module_i nte rne _2
19
20 import module_externe 15.5 Conseils sur la conception d’un script
21
22 UNE_CONSTANTE = valeur Voici quelques conseils pour vous aider à concevoir un script Python.
23 U N E _ AU T R E _ C O N S TA N T E = un e_autr e_valeu r
24 — Réfléchissez avec un papier, un crayon. . . et un cerveau (voire même plusieurs) ! Reformulez avec des mots en français
25
26 class UneSuperClasse (): (ou en anglais) les consignes qui vous ont été données ou le cahier des charges qui vous a été communiqué. Dessinez
27 """ R é sum é de la docstring d é crivant la classe . ou construisez des schémas si cela vous aide.
28
29 Description d é taill é e ligne 1 — Découpez en fonctions chaque élément de votre programme. Vous pourrez ainsi tester chaque élément indépendam-
30 Description d é taill é e ligne 2 ment du reste. Pensez à écrire les docstrings en même temps que vous écrivez vos fonctions.
31 Description d é taill é e ligne 3
32 """ — Quand l’algorithme est complexe, commentez votre code pour expliquer votre raisonnement. Utiliser des fonctions (ou
33
méthodes) encore plus petites peut aussi être une solution.
34 def __init__ ( self ):
35 """ R é sum é de la docstring d é crivant le constructeur . — Documentez-vous. L’algorithme dont vous avez besoin existe-t-il déjà dans un autre module ? Existe-t-il sous la forme
36
37 Description d é taill é e ligne 1
de pseudo-code ? De quels outils mathématiques avez-vous besoin dans votre algorithme ?
38 Description d é taill é e ligne 2 — Si vous créez ou manipulez une entité cohérente avec des propriétés propres, essayez de construire une classe. Jetez,
39 Description d é taill é e ligne 3
40 """ pour cela, un œil au chapitre 19 Avoir la classe avec les objets.
41 [...] — Utilisez des noms de variables explicites, qui signifient quelque chose. En lisant votre code, on doit comprendre ce que
42
43 def une_m é thode_simple ( self ):
vous faites. Choisir des noms de variables pertinents permet aussi de réduire les commentaires.
44 """ Docstring d ' une ligne d é crivant la m é thode .""" — Quand vous construisez une structure de données complexe (par exemple une liste de dictionnaires contenant d’autres
45 [...] objets), documentez et illustrez l’organisation de cette structure de données sur un exemple simple.
46
47 def une_m é thode_ complexe ( self , arg1 ): — Testez toujours votre code sur un jeu de données simple pour pouvoir comprendre rapidement ce qui se passe. Par
48 """ R é sum é de la docstring d é crivant la m é thode . exemple, une séquence de 1000 bases est plus facile à gérer que le génome humain ! Cela vous permettra également
49
50 Description d é taill é e ligne 1 de retrouver plus facilement une erreur lorsque votre programme ne fait pas ce que vous souhaitez.
51 Description d é taill é e ligne 2
52 Description d é taill é e ligne 3 — Lorsque votre programme « plante », lisez le message d’erreur. Python tente de vous expliquer ce qui ne va pas. Le
53 """ numéro de la ligne qui pose problème est aussi indiqué.
54 [...]
55 return un_truc — Discutez avec des gens. Faites tester votre programme par d’autres. Les instructions d’utilisation sont-elles claires ?
56 — Si vous distribuez votre code :
57
58 def u n e _ f o n c t i o n _ c o m p l e x e ( arg1 , arg2 , arg3 ): — Rédigez une documentation claire.
59 """ R é sum é de la docstring d é crivant la fonction . — Testez votre programme (jetez un œil aux tests unitaires 10 ).
60
61 Description d é taill é e ligne 1 — Précisez une licence d’utilisation. Voir par exemple le site Choose an open source license 11 .
62 Description d é taill é e ligne 2
63 Description d é taill é e ligne 3
64 """
65
66
[...]
return une_chose
15.6 Pour terminer : la PEP 20
67
68 La PEP 20 est une sorte de réflexion philosophique avec des phrases simples qui devraient guider tout programmeur.
69 def u n e _ f o n ct i o n _ s i m p l e ( arg1 , arg2 ):
70 """ Docstring d ' une ligne d é crivant la fonction .""" Comme les développeurs de Python ne manque pas d’humour, celle-ci est accessible sous la forme d’un « œuf de Pâques »
71 [...] (easter egg en anglais) ou encore « fonctionnalité cachée d’un programme » en important un module nommé this :
72 return autre_chose
73 1 >>> import this
74 2 The Zen of Python , by Tim Peters
75 if __name__ == " __main__ ": 3
76 # ici d é bute le programme principal 4 Beautiful is better than ugly .
77 [...] 5 Explicit is better than implicit .
6 Simple is better than complex .
7 Complex is better than complicated .
8 Flat is better than nested .
Lignes 1 à 9. Cette docstring décrit globalement le script. Cette docstring (ainsi que les autres) seront visibles si on importe 9 Sparse is better than dense .
le script en tant que module, puis en invoquant la commande help() (voir chapitre 14 Création de modules). 10 Readability counts .
Lignes 11 à 15. On définit ici un certain nombres de variables avec des doubles underscores donnant quelques informations 10. https://fr.wikipedia.org/wiki/Test_unitaire
sur la version du script, les auteurs, etc. Il s’agit de métadonnées que la commande help() pourra afficher. Bien sûr, ces 11. https://choosealicense.com/
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 135 136 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
15.6. Pour terminer : la PEP 20 Chapitre 15. Bonnes pratiques en programmation Python
Ici, egrep affiche toutes les lignes du fichier du virus de l’herpès (herp_virus.gbk) dans lesquelles la regex ˆDEF
(c’est-à-dire le mot DEF en début de ligne) est retrouvée.
Remarque
Il est intéressant de faire un point sur le vocabulaire utilisé en anglais et en français. En général, on utilise le verbe to
match pour indiquer qu’une regex « a fonctionné ». Bien qu’il n’y ait pas de traduction littérale en français, on peut utiliser
les verbes « retrouver » ou « correspondre ». Par exemple, on pourra traduire l’expression « The regex matches the line » par
« La regex est retrouvée dans la ligne » ou encore « La regex correspond dans la ligne ».
12. https://realpython.com/python-code-quality/ Après avoir introduit le vocabulaire des regex, voici quelques éléments de syntaxe des métacaractères :
13. https://openclassrooms.com/fr/courses/4425111-perfectionnez-vous-en-python/4464230-assimilez-les-bonnes-pratiques-de-la-pep-8
14. https://realpython.com/python-program-structure/ 1. https://docs.python.org/fr/3/library/re.html
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 137 138
16.1. Définition et syntaxe Chapitre 16. Expressions régulières et parsing Chapitre 16. Expressions régulières et parsing 16.2. Quelques ressources en ligne
\s remplace n’importe quel « espace blanc » (whitespace) (s signifie space), équivalent à [ \t\n\r\f]. La notion Il existe également la fonction fullmatch() qui renvoie un objet du type SRE_Match si et seulement si l’expression
d’espace blanc a été abordée dans le chapitre 10 Plus sur les chaînes de caractères. Les espaces blancs les plus régulière correspond exactement à la chaîne de caractères.
classiques sont l’espace , la tabulation \t, le retour à la ligne \n, mais il en existe d’autres comme \r et \f que nous 1 >>> animaux = " tigre "
ne développerons pas ici. \s est très pratique pour détecter une combinaison d’espace(s) et/ou de tabulation(s). 2 >>> re . fullmatch (" tigre " , animaux )
3 >>> animaux = " tigre "
Comme vous le constatez, les métacaractères sont nombreux et leur signification est parfois difficile à maîtriser. Faites 4 >>> re . fullmatch (" tigre " , animaux )
5 < _sre . SRE_Match object ; span =(0 , 5) , match = ' tigre ' >
particulièrement attention aux métacaractères ., + et * qui, combinés ensemble, peuvent donner des résultats ambigus.
Il est important de savoir par ailleurs que les regex sont « avides » (greedy en anglais) lorsqu’on utilise les métacaractères 2. https://regexone.com/
3. https://regexr.com/
+ et *. C’est-à-dire que la regex cherchera à « s’étendre » au maximum. Par exemple, si on utilise la regex A+ pour faire une
4. https://extendsclass.com/regex-tester.html#python
recherche dans la chaîne TTTAAAAAAAAGC, tous les A de cette chaîne (8 en tout) seront concernés, bien que AA, AAA, etc. « 5. https://pythex.org/
fonctionnent » également avec cette regex. 6. https://www.regular-expressions.info
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 139 140 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
16.3. Le module re Chapitre 16. Expressions régulières et parsing Chapitre 16. Expressions régulières et parsing 16.4. Exercices
De manière générale, nous vous recommandons l’usage de la fonction search(). Si vous souhaitez avoir une correspon- 1 >>> regex = re . compile ("[0 -9]+\.[0 -9]+")
dance avec le début de la chaîne de caractères comme dans la fonction match(), vous pouvez toujours utiliser l’accroche de 2 >>> resultat = regex . findall (" pi vaut 3.14 et e vaut 2.72")
3 >>> resultat
début de ligne ˆ. Si vous voulez une correspondance exacte comme dans la fonction fullmatch(), vous pouvez utiliser les 4 [ '3.14 ' , '2.72 ']
métacaractères ˆ et $, par exemple ˆtigre$.
L’utilisation des groupes entre parenthèses est également possible et ceux-ci sont alors renvoyés sous la forme de tuples.
1 >>> regex = re . compile ("([0 -9]+)\.([0 -9]+)")
16.3.3 Compilation d’expressions régulières 2 >>> resultat = regex . findall (" pi vaut 3.14 et e vaut 2.72")
3 >>> resultat
4 [( '3 ' , '14 ') , ( '2 ' , '72 ')]
Lorsqu’on a besoin de tester la même expression régulière sur plusieurs milliers de chaînes de caractères, il est pratique
de compiler préalablement la regex à l’aide de la fonction compile() qui renvoie un objet de type SRE_Pattern :
1 >>> regex = re . compile ("^ tigre ") 16.3.6 La méthode .sub()
2 >>> regex
3 < _sre . SRE_Pattern object at 0 x7fefdafd0df0 >
Enfin, la méthode .sub() permet d’effectuer des remplacements assez puissants. Par défaut la méthode .sub(chaine1,
On peut alors utiliser directement cet objet avec la méthode .search() : chaine2) remplace toutes les occurrences trouvées par l’expression régulière dans chaine2 par chaine1. Si vous souhaitez
1 >>> animaux = " girafe tigre singe " ne remplacer que les n premières occurrences, utilisez l’argument count=n :
2 >>> regex . search ( animaux ) 1 >>> regex = re . compile ("[0 -9]+\.[0 -9]+")
3 >>> animaux = " tigre singe " 2 >>> regex . sub (" quelque chose " , " pi vaut 3.14 et e vaut 2.72")
4 >>> regex . search ( animaux ) 3 ' pi vaut quelque chose et e vaut quelque chose '
5 < _sre . SRE_Match object at 0 x7fefdaefe718 > >>> regex . sub (" quelque chose " , " pi vaut 3.14 et e vaut 2.72" , count =1)
>>> animaux = " singe tigre "
4
6
5 ' pi vaut quelque chose et e vaut 2.72 '
7 >>> regex . search ( animaux )
Encore plus puissant, il est possible d’utiliser dans le remplacement des groupes qui ont été « capturés » avec des paren-
thèses.
16.3.4 Groupes 1 >>> regex = re . compile ("([0 -9]+)\.([0 -9]+)")
2 >>> phrase = " pi vaut 3.14 et e vaut 2.72"
L’intérêt de l’objet de type SRE_Match renvoyé par Python lorsqu’une regex trouve une correspondance dans une chaîne 3 >>> regex . sub (" a p p r o x im at i v e m e n t \\1" , phrase )
4 ' pi vaut app r o x i m a t i v e m e n t 3 et e vaut vaut a p p r o x i ma ti v e m e n t 2 '
de caractères est de pouvoir ensuite récupérer certaines zones précises : 5 >>> regex . sub (" a p p r o x im at i v e m e n t \\1 ( puis .\\2)" , phrase )
6 ' pi vaut app r o x i m a t i v e m e n t 3 ( puis .14) et e vaut a p p r o xi m a t i v e m e n t 2 ( puis .72) '
1 >>> regex = re . compile ("([0 -9]+)\.([0 -9]+)")
Si vous avez capturé des groupes, il suffit d’utiliser \\1, \\2 (etc.) pour utiliser les groupes correspondants dans la chaîne
Dans cet exemple, on recherche un nombre décimal, c’est-à-dire une chaîne de caractères : de caractères substituée. On notera que la syntaxe générale pour récupérer des groupes dans les outils qui gèrent les regex est
— qui débute par un ou plusieurs chiffres [0-9]+, \1, \2, etc. Toutefois, Python nous oblige à mettre un deuxième backslash car il y a ici deux niveaux : un premier niveau
— suivi d’un point \. (le point a d’habitude une signification de métacaractère, donc il faut l’échapper avec \ pour qu’il Python où on veut mettre un backslash littéral (donc \\), puis un second niveau regex dans lequel on veut retrouver \1. Si cela
retrouve sa signification de point), est confus, retenez seulement qu’il faut mettre un \\ devant le numéro de groupe.
— et qui se termine encore par un ou plusieurs chiffres [0-9]+. Enfin, sachez que la réutilisation d’un groupe précédemment capturé est aussi utilisable lors d’une utilisation classique de
Les parenthèses dans la regex créent des groupes ([0-9]+ deux fois) qui seront récupérés ultérieurement par la méthode regex. Par exemple :
.group().
1 >>> re . search ("( pan )\\1" , " bambi et panpan ")
1 >>> resultat = regex . search (" pi vaut 3.14") 2 < _sre . SRE_Match object ; span =(9 , 15) , match = ' panpan ' >
2 >>> resultat . group (0) 3 >>> re . search ("( pan )\\1" , " le pistolet a fait pan !")
3 '3.14 ' 4 >>>
4 >>> resultat . group (1)
5 '3 ' Dans la regex (pan)\\1, on capture d’abord le groupe (pan) grâce aux parenthèses (il s’agit du groupe 1 puisque c’est le
>>> resultat . group (2)
6
7 '14 ' premier jeu de parenthèses), immédiatement suivi du même groupe grâce au \\1. Dans cet exemple, on capture donc le mot
8 >>> resultat . start () panpan (lignes 1 et 2). Si, par contre, on a une seule occurrence du mot pan, cette regex ne fonctionne pas, ce qui est le cas
9 8
10 >>> resultat . end ()
ligne 3.
11 12 Bien sûr, si on avait eu un deuxième groupe, on aurait pu le réutiliser avec \\2, un troisième groupe avec \\3, etc.
Nous espérons vous avoir convaincu de la puissance du module re et des expressions régulières. Alors, plus de temps à
La totalité de la correspondance est donnée par .group(0), le premier élément entre parenthèses est donné par .group(1) perdre, à vos regex !
et le second par .group(2).
Les méthodes .start() et .end() donnent respectivement la position de début et de fin de la zone qui correspond à la
regex. Notez que la méthode .search() ne renvoie que la première zone qui correspond à l’expression régulière, même s’il 16.4 Exercices
en existe plusieurs :
1 >>> resultat = regex . search (" pi vaut 3.14 et e vaut 2.72") Conseil : pour ces exercices, créez des scripts puis exécutez-les dans un shell.
2 >>> resultat . group (0)
3 '3.14 '
16.4.1 Regex de base
Dans cet exercice, nous allons manipuler le fichier GenBank NC_001133.gbk 7 correspondant au chromosome I de la
16.3.5 La méthode .findall() levure Saccharomyces cerevisiae.
Créez un script regex_genbank.py :
Pour récupérer chaque zone, s’il y en a plusieurs, vous pouvez utiliser la méthode .findall() qui renvoie une liste des
éléments en correspondance. 7. https://python.sdv.univ-paris-diderot.fr/data-files/NC_001133.gbk
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 141 142 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
16.4. Exercices Chapitre 16. Expressions régulières et parsing Chapitre 16. Expressions régulières et parsing 16.4. Exercices
— qui recherche le mot DEFINITION en début de ligne dans le fichier GenBank, puis affiche la ligne correspondante ; — Le numéro qui s’incrémente débutera à 1 et sera affiché sur 5 caractères avec des 0 à sa gauche si nécessaires (formatage
— qui recherche tous les journaux (mot-clé JOURNAL) dans lesquels ont été publiés les travaux sur cette séquence, puis {:05d}).
affiche les lignes correspondantes.
Conseils : 16.4.5 Le défi du dé-htmliseur (exercice +++)
— Vous utiliserez des regex pour trouver les lignes demandées.
— Vous trouverez des explications sur le format GenBank et des exemples de code dans l’annexe A Quelques formats de Le format HTML permet d’afficher des pages web dans un navigateur. Il s’agit d’un langage à balise qui fonctionne avec
données rencontrés en biologie. des balises ouvrantes <balise> et des balises fermantes </balise>.
Créez un script dehtmliseur.py qui lit le fichier fichier_a_dehtmliser.html 10 au format HTML et qui renvoie à
l’écran tout le texte de ce fichier sans les balises HTML.
16.4.2 Enzyme de restriction
Nous vous conseillons tout d’abord d’ouvrir le fichier HTML dans un éditeur de texte et de bien l’observer. N’hésitez pas
Une enzyme de restriction est une protéine capable de couper une molécule d’ADN. Cette coupure se fait sur le site de à vous aider des sites mentionnés dans les ressources en ligne
restriction de l’ADN qui correspond à une séquence particulière de nucléotides (bases).
Pour chacune des enzymes ci-dessous, déterminez les expressions régulières qui décrivent leurs sites de restriction. Le 16.4.6 Nettoyeur de doublons (exercice +++)
symbole N correspond aux bases A, T, C ou G. W correspond à A ou T . Y correspond à C ou T. R correspond à A ou G.
Téléchargez le fichier breves_doublons.txt 11 qui contient des mots répétés deux fois. Par exemple :
Enzyme Site de restriction 1 Le cin é ma est devenu parlant , la radio radio finira en images .
2 La sardine , c ' est un petit petit poisson sans t ê te qui vit dans l ' huile .
HinFI GANTC 3 [...]
EcoRII CCWGG Écrivez un script ote_doublons.py qui lit le fichier breves_doublons.txt et qui supprime tous les doublons à l’aide
BbvBI GGYRCC d’une regex. Le script affichera le nouveau texte à l’écran.
BcoI CYCGRG Conseil : utilisez la méthode .sub().
Psp5II RGGWCCY
BbvAI GAANNNNTTC
Conseils :
— Vous trouverez des explications sur le format FASTA et des exemples de code dans l’annexe A Quelques formats de
données rencontrés en biologie.
— La ligne de commentaire d’une séquence au format FASTA est de la forme
>sp|O95139|NDUB6_HUMAN NADH dehydrogenase [...]
Elle débute toujours pas le caractère >. Le numéro d’accession O95139 se situe entre le premier et le second symbole
| (symbole pipe). Attention, il faudra « échapper » ce symbole car il a une signification particulière dans une regex.
8. https://python.sdv.univ-paris-diderot.fr/data-files/cigale_fourmi.txt 10. https://python.sdv.univ-paris-diderot.fr/data-files/fichier_a_dehtmliser.html
9. https://python.sdv.univ-paris-diderot.fr/data-files/human-proteome.fasta 11. https://python.sdv.univ-paris-diderot.fr/data-files/breves_doublons.txt
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 143 144 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.1. Module NumPy
Par ailleurs, lorsqu’on demande à Python d’afficher le contenu d’un objet array, le mot array et les symboles ([ et ])
sont utilisés pour le distinguer d’une liste (délimitée par les caractères [ et ]) ou d’un tuple (délimité par les caractères ( et )).
Remarque
Un objet array ne contient que des données homogènes, c’est-à-dire d’un type identique.
Il est possible de créer un objet array à partir d’une liste contenant des entiers et des chaînes de caractères, mais dans ce
Chapitre 17 cas, toutes les valeurs seront comprises par NumPy comme des chaînes de caractères :
1 >>> a = np . array ([1 , 2 , " tigre "])
2 >>> a
3 array ([ '1 ' , '2 ' , ' tigre '] , dtype = ' < U21 ')
>>> type ( a )
Quelques modules d’intérêt en bioinformatique 4
5 < class ' numpy . ndarray ' >
De même, il est possible de créer un objet array à partir d’une liste constituée d’entiers et de floats, mais toutes les valeurs
seront alors comprises par NumPy comme des floats :
1 >>> b = np . array ([1 , 2 , 3.5])
Nous allons aborder dans ce chapitre quelques modules très importants en bioinformatique. Le premier NumPy permet 2 >>> b
3 array ([1. , 2. , 3.5])
notamment de manipuler des vecteurs et des matrices. Le module Biopython permet de travailler sur des données biologiques, 4 >>> type ( b )
comme des séquences (nucléiques et protéiques) ou des structures (fichiers PDB). Le module matplotlib permet de créer 5 < class ' numpy . ndarray ' >
des graphiques depuis Python. Enfin, le module pandas est très performant pour l’analyse de données, et scipy étend les
Ici, la notation 1. indique qu’il s’agit du float 1.0000... et pas de l’entier 1.
possibilités offertes par NumPy, notamment en proposant des algorithmes couramment utilisés en calcul scientifique.
Ces modules ne sont pas fournis avec la distribution Python de base (contrairement à tous les autres modules vus précé-
demment). Avec la distribution Miniconda que nous vous avons conseillé d’utiliser (consultez pour cela la documentation en Sur un modèle similaire à la fonction range(), la fonction arange() permet de construire un array à une dimension de
ligne 1 ), vous pouvez rapidement les installer avec la commande : manière simple.
1 $ conda install -y numpy pandas matplotlib scipy biopython 1 >>> np . arange (10)
2 array ([0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9])
Dans ce chapitre, nous vous montrerons quelques exemples d’utilisation de ces modules pour vous convaincre de leur
pertinence. Comme avec range(), on peut spécifier en argument une borne de début, une borne de fin et un pas :
1 >>> np . arange (10 , 0 , -1)
2 array ([10 , 9 , 8 , 7 , 6 , 5, 4, 3, 2, 1])
17.1 Module NumPy Un autre avantage de la fonction arange() est qu’elle génère des objets array qui contiennent des entiers ou des floats
Le module NumPy 2 est incontournable en bioinformatique. Il permet d’effectuer des calculs sur des vecteurs ou des selon l’argument qu’on lui passe :
matrices, élément par élément, via un nouveau type d’objet appelé array. 1 >>> np . arange (10)
2 array ([0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9])
On charge le module NumPy avec la commande : 3 >>> np . arange (10.0)
1 >>> import numpy 4 array ([ 0. , 1. , 2. , 3. , 4. , 5. , 6. , 7. , 8. , 9.])
On utilise très souvent un nom raccourci pour NumPy : La différence fondamentale entre un objet array à une dimension et une liste (ou un tuple) est que celui-ci est considéré
1 >>> import numpy as np comme un vecteur. Par conséquent, on peut effectuer des opérations élément par élément sur ce type d’objet, ce qui est bien
commode lorsqu’on analyse de grandes quantités de données. Regardez ces exemples :
1 >>> v = np . arange (4)
2 >>> v
17.1.1 Objets de type array 3 array ([0 , 1 , 2 , 3])
4 >>> v + 1
Les objets de type array correspondent à des tableaux à une ou plusieurs dimensions et permettent d’effectuer du calcul 5 array ([1 , 2 , 3 , 4])
>>> v + 0.1
vectoriel. La fonction array() convertit un container (comme une liste ou un tuple) en un objet de type array. Voici un 6
7 array ([ 0.1 , 1.1 , 2.1 , 3.1])
exemple simple de conversion d’une liste à une dimension en objet array : 8 >>> v * 2
9 array ([0 , 2 , 4 , 6])
1 >>> import numpy as np 10 >>> v * v
2 >>> a = [1 , 2 , 3] 11 array ([0 , 1 , 4 , 9])
3 >>> np . array ( a )
4 array ([1 , 2 , 3]) Avec les listes, ces opérations n’auraient été possibles qu’en utilisant des boucles. Nous vous encourageons donc à utiliser
5 >>> b = np . array ( a )
6 >>> b dorénavant les objets array lorsque vous aurez besoin de faire des opérations élément par élément.
7 array ([1 , 2 , 3]) Notez également que, dans le dernier exemple de multiplication (ligne 10), l’array final correspond à la multiplication
8 >>> type ( b )
9 < type ' numpy . ndarray ' > élément par élément des deux arrays initiaux.
Nous avons converti la liste [1, 2, 3] en array. Nous aurions obtenu le même résultat si nous avions converti le tuple
(1, 2, 3) en array. 17.1.2 Array et dimensions
1. https://python.sdv.univ-paris-diderot.fr/livre-dunod Il est aussi possible de construire des objets arrays à deux dimensions, il suffit de passer en argument une liste de listes à
2. http://numpy.scipy.org/ la fonction array() :
145 146 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.1. Module NumPy Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.1. Module NumPy
1 >>> a = np . arange (0 , 6)
2 >>> a
3 array ([0 , 1 , 2 , 3 , 4 , 5])
4 >>> a . shape
5 (6 ,)
6 >>> b = a . reshape ((2 , 3))
7 >>> b
8 array ([[0 , 1 , 2] ,
9 [3 , 4 , 5]])
10 >>> b . shape
11 (2 , 3)
12 >>> a
13 array ([0 , 1 , 2 , 3 , 4 , 5])
Notez bien que le array a n’a pas été modifié et que a.reshape((2, 3)) n’est pas la même chose que a.reshape((3,
2)) :
1 >>> c = a . reshape ((3 , 2))
2 >>> c
3 array ([[0 , 1] ,
4 [2 , 3] ,
F IGURE 17.1 – Définition des lignes et colonnes dans un array 2D. 5 [4 , 5]])
6 >>> c . shape
7 (3 , 2)
>>> w = np . array ([[1 , 2] , [3 , 4] , [5 , 6]])
1
2 >>> w La méthode .reshape() attend que les nouvelles dimensions soient compatibles avec la dimension initiale de l’objet
3 array ([[1 , 2] , array, c’est-à-dire que le nombre d’éléments contenus dans les différents arrays soit le même. Dans nos exemples précédents,
4 [3 , 4] , 6 = 2 × 3 = 3 × 2.
5 [5 , 6]])
Si les nouvelles dimensions ne sont pas compatibles avec les dimensions initiales, la méthode .reshape() génère une
On peut aussi créer des tableaux à trois dimensions en passant comme argument à la fonction array() une liste de listes erreur.
de listes : 1 >>> a = np . arange (0 , 6)
2 >>> a
1 >>> x = np . array ([[[1 , 2] , [2 , 3]] , [[4 , 5] , [5 , 6]]]) 3 array ([0 , 1 , 2 , 3 , 4 , 5])
2 >>> x 4 >>> a . shape
3 array ([[[1 , 2] , 5 (6 ,)
4 [2 , 3]] , 6 >>> d = a . reshape ((3 , 4))
5
7 Traceback ( most recent call last ):
6 [[4 , 5] , 8 File " < stdin >" , line 1 , in < module >
7 [5 , 6]]]) 9 ValueError : cannot reshape array of size 6 into shape (3 ,4)
La fonction array() peut créer des tableaux à n’importe quel nombre de dimensions. Toutefois ça devient vite compliqué La méthode .resize() par contre ne déclenche pas d’erreur dans une telle situation et ajoute des 0 jusqu’à ce que le
lorsqu’on dépasse trois dimensions. Retenez qu’un objet array à une dimension peut être assimilé à un vecteur et un array à nouvel array soit rempli, ou bien coupe la liste initiale.
deux dimensions à une matrice. Nous nous focaliserons dans la suite sur des arrays 1D ou 2D. 1 >>> a = np . arange (0 , 6)
2 >>> a . shape
Avant de continuer, il est important de définir comment sont organisés ces arrays 2D qui représentent des matrices. Il 3 (6 ,)
s’agit de tableaux de nombres qui sont organisés en lignes et en colonnes comme le montre la figure 17.1. Les indices indiqués 4 >>> a . resize ((3 , 3) , refcheck = False )
dans cette figure seront définis un peu plus loin dans la rubrique Indices. 5 >>> a . shape
6 (3 , 3)
Voici quelques attributs intéressants pour décrire un objet array : 7 >>> a
— .ndim renvoie le nombre de dimensions (par exemple, 1 pour un vecteur et 2 pour une matrice). 8 array ([[0 , 1 , 2] ,
[3 , 4 , 5] ,
— .shape renvoie les dimensions sous forme d’un tuple. Dans le cas d’une matrice (array à deux dimensions), la pre-
9
10 [0 , 0 , 0]])
mière valeur du tuple correspond au nombre de lignes et la seconde au nombre de colonnes.
— .size renvoie le nombre total d’éléments contenus dans l’array. 1 >>> b = np . arange (0 , 10)
2 >>> b . shape
1 >>> v = np . arange (4) 3 (10 ,)
2 >>> v 4 >>> b . resize ((2 , 3) , refcheck = False )
3 array ([0 , 1 , 2 , 3]) 5 >>> b . shape
4 >>> v . ndim 6 (2 , 3)
5 1 7 >>> b
6 >>> v . shape 8 array ([[0 , 1 , 2] ,
7 (4 ,) 9 [3 , 4 , 5]])
8 >>> v . size
9 4
10 >>> w = np . array ([[1 , 2] , [3 , 4] , [5 , 6]])
11 >>> w Attention
12 array ([[1 , 2] , Attention, cette modification de la forme de l’array par la méthode .resize() est faite « sur place » (in place), c’est-à-dire
[3 , 4] ,
que la méthode ne renvoie rien mais l’array est bel et bien modifié (à l’image des méthodes sur les listes comme .reverse(),
13
14 [5 , 6]])
15 >>> w . ndim cf. chapitre 11 Plus sur les listes). Si l’option refcheck=False n’est pas présente, Python peut parfois renvoyer une erreur
16 2
17 >>> w . shape s’il existe des références vers l’array qu’on souhaite modifier.
18 (3 , 2)
19 >>> w . size
20 6
Il existe aussi la fonction np.resize() qui, dans le cas d’un nouvel array plus grand que l’array initial, va répéter l’array
Et la méthode .reshape() renvoie un nouvel array avec les dimensions spécifiées : initial afin de remplir les cases manquantes :
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 147 148 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.1. Module NumPy Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.1. Module NumPy
Lignes 5 à 8. La syntaxe a[i,:] renvoie la ligne d’indice i, et a[:,j] renvoie la colonne d’indice j. Les tranches sont
évidemment aussi utilisables sur un array à deux dimensions.
Lignes 9 à 10. La syntaxe a[i, j] renvoie l’élément à la ligne d’indice i et à la colonne d’indice j. Notez que NumPy
17.1.3 Méthodes de calcul sur les arrays et l’argument axis suit la convention mathématiques des matrices 4 , à savoir, on définit toujours un élément par sa ligne puis par sa colonne.
Chaque array NumPy qui est créé possède une multitude de méthodes. Nombre d’entre elles permettent de faire des En mathématiques, l’élément ai j d’une matrice A se trouve à la ime ligne et à la jme colonne.
calculs de base comme .mean() pour la moyenne, .sum() pour la somme, .std() pour l’écart-type, .max() pour extraire le
maximum, .min() pour extraire le minimum, etc. La liste exhaustive est ici 3 . Par défaut, chacune de ces méthodes effectuera Remarque
l’opération sur l’array entier, quelle que soit sa dimensionnalité. Par exemple : — Pour un array 2D, si un seul indice est donné, par exemple a[i], on récupère la ligne d’indice i sous forme d’array
1 >>> import random as rd 1D :
2 >>> l = list ( range (8)) 1 >>> a
3 >>> rd . shuffle ( l ) 2 array ([[1 , 2] ,
4 >>> l 3 [3 , 4]])
5 [2 , 7 , 6 , 4 , 0 , 3 , 1 , 5] 4 >>> a [0]
6 >>> a = np . resize (l , (4 , 2)) 5 array ([1 , 2])
7 >>> a
6 >>> a [1]
8 array ([[2 , 7] ,
7 array ([3 , 4])
9 [6 , 4] ,
[0 , 3] ,
10
11 [1 , 5]])
— Pour cette raison, la syntaxe a[i][j] est également valide pour récupérer un élément :
12 >>> a . max () 1 >>> a
13 7 2 array ([[1 , 2] ,
3 [3 , 4]])
La méthode .max() nous a bien renvoyé la valeur maximale 7. Un argument très utile existant dans toutes ces méthodes 4 >>> a [1 , 1]
est axis. Pour un array 2D, axis=0 signifie qu’on fera l’opération le long de l’axe 0, à savoir les lignes. C’est-à-dire que 5 4
6 >>> a [1][1]
l’opération se fait en faisant varier les lignes. On récupère ainsi une valeur par colonne : 7 4
3. https://numpy.org/doc/stable/reference/arrays.ndarray.html#calculation 4. https://fr.wikipedia.org/wiki/Matrice_(math%C3%A9matiques)#D%C3%A9finitions
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 149 150 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.1. Module NumPy Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.1. Module NumPy
Bien que cela soit possible, nous vous recommandons tout de même la syntaxe a[i, j] qui est plus proche de la définition construisent des objets array contenant des 0 ou des 1. Il suffit de leur passer en argument un tuple indiquant les dimensions
mathématiques d’un élément de matrice 5 . voulues.
1 >>> np . zeros ((2 , 3))
2 array ([[0. , 0. , 0.] ,
3 [0. , 0. , 0.]])
4 >>> np . ones ((3 , 3))
17.1.5 Copie d’arrays 5 array ([[1. , 1. , 1.] ,
6 [1. , 1. , 1.] ,
Comme pour les listes, nous attirons votre attention sur la copie d’arrays : 7 [1. , 1. , 1.]])
1 >>> a = np . arange (5) Par défaut, les fonctions zeros() et ones() génèrent des floats, mais vous pouvez demander des entiers en passant le
>>> a
type (par exemple int, float, etc.) en second argument :
2
3 array ([0 , 1 , 2 , 3 , 4])
>>> b = a
>>> np . zeros ((2 ,3) , int )
4
1
>>> b [2] = -300
array ([[0 , 0 , 0] ,
5
6 >>> b 2
Afin d’éviter le problème, vous pouvez soit utiliser la fonction np.array() qui crée une nouvelle copie distincte de Nous construisons ainsi une matrice constituée de 2 lignes et 3 colonnes. Celle-ci ne contient que le chiffre 7 sous formes
l’array initial, soit la fonction copy.deepcopy() comme pour les listes (cf. chapitre 11 Plus sur les listes) : d’entiers (int) dans le premier cas et de floats dans le second.
Le module numpy contient aussi des fonctions pour lire des données à partir de fichiers et créer des arrays automatique-
1 >>> a = np . full ((2 , 2) , 0)
2 >>> a ment. Cela se révèle bien pratique car la plupart du temps les données que l’on analyse proviennent de fichiers. La fonction la
3 array ([[0 , 0] , plus simple à prendre en main est np.loadtxt(). Celle-ci lit un fichier organisé en lignes / colonnes. Par exemple, imaginons
[0 , 0]])
4
5 >>> b = np . array ( a ) que nous ayons un fichier donnees.dat contenant :
6 >>> b [1 , 1] = -300 1 1 7 310
7 >>> c = copy . deepcopy ( a ) 2 15 -4 35
8 >>> c [1 , 1] = -500 3 78 95 79
9 >>> a
10 array ([[0 , 0] , La fonction prend en argument le nom du fichier et renvoie un array 2D directement :
11 [0 , 0]])
12 >>> b 1 >>> np . loadtxt (" donnees . dat ")
13 array ([[ 0, 0] , 2 array ([[ 1. , 7. , 310.] ,
14 [ 0 , -300]]) 3 [ 15. , -4. , 35.] ,
15 >>> c 4 [ 78. , 95. , 79.]])
16 array ([[ 0, 0] ,
17 [ 0 , -500]]) Pratique, non ? Attention toutefois aux points suivants :
— chaque ligne doit avoir le même nombre de colonnes, la fonction ne gère pas les données manquantes ;
La fonction np.full() est expliquée dans la rubrique suivante.
— chaque donnée est convertie en float, donc si une chaîne est rencontrée la fonction renvoie une erreur ;
— par défaut, les données doivent être séparées par n’importe quelle combinaison d’espace(s) et/ou de tabulations.
Remarque Nous vous conseillons vivement de consulter la documentation complète 6 de cette fonction. np.loadtxt() contient tout
On pourra noter que la stratégie b = np.array(a) fait bien une copie distincte de l’array a quelle que soit sa dimen- un tas d’arguments par mot-clé permettant de récupérer telles ou telles lignes / colonnes, ignorer des lignes de commentaire,
sionnalité. Ceci n’était pas le cas avec la fonction list() pour les copies de listes à partir de la dimensionnalité 2 : changer le séparateur par défaut (par exemple la virgule , pour les fichiers .csv), etc., qui peuvent se révéler commodes.
1 >>> liste_1 = [[0 , 0] , [1 , 1]] L’opération inverse consistant à sauver un array dans un fichier se fait avec la fonction np.savetxt() :
2 >>> liste_2 = list ( liste_1 )
3 >>> liste_3 = copy . deepcopy ( liste_1 ) 1 >>> a = np . reshape ( range (1 , 10) , (3 , 3))
4 >>> liste_1 [1][1] = -365 2 >>> a
5 >>> liste_2 3 array ([[1 , 2 , 3] ,
6 [[0 , 0] , [1 , -365]] 4 [4 , 5 , 6] ,
7 >>> liste_3 5 [7 , 8 , 9]])
8 [[0 , 0] , [1 , 1]] 6 >>> np . savetxt (" out . dat " , a )
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 151 152 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.1. Module NumPy Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.1. Module NumPy
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 153 154 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.1. Module NumPy Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.1. Module NumPy
Lignes 12 à 15. La fonction eig() renvoie un tuple dont le premier élément (d’indice 0) correspond aux valeurs propres 5 array ([2 , 5 , 8])
6 >>> c3
et le second (d’indice 1) aux vecteurs propres. Une façon commode de récupérer ces éléments est d’utiliser cette fonction avec 7 array ([3 , 6 , 9])
l’affectation multiple :
1 >>> eigvals , eigvecs = np . linalg . eig ( a )
>>> eigvals
2
3 array ([1. , 2. , 3.])
17.1.10 Masques booléens
4 >>> eigvecs
5 array ([[1. , 0. , 0.] , Une des grandes puissance des arrays NumPy est qu’ils supportent les masques booléens. Avant de les définir, il est
6 [0. , 1. , 0.] , important d’introduire le concept d’arrays de booléens. Jusqu’à maintenant nous avions définis uniquement des arrays avec
[0. , 0. , 1.]])
7
8 >>> eigvecs [0]
des types numériques int ou float. Il est tout à fait possible de définir des arrays de booléens. La fonction np.full() vue
9 array ([1. , 0. , 0.]) ci-dessus nous permet d’en construire facilement :
10 >>> eigvecs [1]
1 >>> np . full ((2 , 2) , True )
11 array ([0. , 1. , 0.])
2 array ([[ True , True ] ,
12 >>> eigvecs [2]
3 [ True , True ]])
13 array ([0. , 0. , 1.])
4 >>> np . full ((2 , 2) , False )
array ([[ False , False ] ,
Lignes 2 et 3. eigvals est un array 1D contenant les 3 valeurs propres. 5
6 [ False , False ]])
Lignes 4 à 13. eigvecs est un array 2D contenant les 3 vecteurs propres (un par ligne), que l’on peut récupérer avec
eigvecs[0], eigvecs[1] et eigvecs[2]. Très bien, mais au premier abord nous n’en voyons pas forcément l’utilité. . . Mais qu’en est-il lorsqu’on utilise les opéra-
teurs de comparaison avec un array ? Et bien cela renvoie un array de booléens !
>>> a = np . reshape ( np . arange (1 , 10) , (3 , 3))
17.1.9 Parcours de matrice et affectation de lignes / colonnes 1
2 >>> a
3 array ([[1 , 2 , 3] ,
Lorqu’on a une matrice, on est souvent amené à la parcourir par ligne ou par colonne. Une fonctionnalité bien commode 4 [4 , 5 , 6] ,
vient du fait que les arrays NumPy sont directement itérables par ligne : 5 [7 , 8 , 9]])
6 >>> a > 5
1 >>> a = np . reshape ( np . arange (1 , 10) , (3 , 3)) 7 array ([[ False , False , False ] ,
2 >>> a 8 [ False , False , True ] ,
3 array ([[1 , 2 , 3] , 9 [ True , True , True ]])
4 [4 , 5 , 6] , 10 >>> a == 2
5 [7 , 8 , 9]]) 11 array ([[ False , True , False ] ,
6 >>> for row in a : 12 [ False , False , False ] ,
7 ... print ( row , type ( row )) 13 [ False , False , False ]])
8 ...
9 [1 2 3] < class ' numpy . ndarray ' > Tous les éléments de l’array satisfaisant la condition seront à True, les autres à False. Encore plus fort, il est possible de
10 [4 5 6] < class ' numpy . ndarray ' >
11 [7 8 9] < class ' numpy . ndarray ' > combiner plusieurs conditions avec les opérateurs logiques & et | (respectivement ET et OU) :
1 >>> a
À chaque itération, la variable row est un array 1D correspondant à chaque ligne de a. Cela est lié au fait que l’utilisation 2 array ([[1 , 2 , 3] ,
d’un indiçage unique a[i] pour un array 2D correspond à sa ligne d’indice i (cf. rubrique Indices ci-dessus). 3 [4 , 5 , 6] ,
[7 , 8 , 9]])
Pour itérer sur les colonnes, on pourra utiliser l’astuce d’itérer sur la transposée de l’array a, c’est-à-dire a.T : 4
5 >>> ( a > 3) & ( a % 2 == 0)
1 >>> for col in a . T : 6 array ([[ False , False , False ] ,
2 ... print ( col , type ( col )) 7 [ True , False , True ] ,
3 ... 8 [ False , True , False ]])
4 [1 4 7] < class ' numpy . ndarray ' > 9 >>> ( a > 3) | ( a % 2 == 0)
5 [2 5 8] < class ' numpy . ndarray ' > 10 array ([[ False , True , False ] ,
6 [3 6 9] < class ' numpy . ndarray ' > 11 [ True , True , True ] ,
12 [ True , True , True ]])
À chaque itération, la variable col est un array 1D correspondant à chaque colonne de a.
On se souvient de l’affectation multiple x, y = 1, 2 qui permettait d’affecter des valeurs à plusieurs variables à la fois. Nous pouvons effectuer deux remarques :
Et bien, il est possible d’utiliser cette fonctionnalité aussi avec les arrays NumPy : — Les opérateurs logiques & et | s’appliquent sur les arrays et sont différents des opérateurs logiques and et or qui eux
1 >>> a
s’appliquent sur les booléens (True ou False) ;
2 array ([[1 , 2 , 3] , — Il est conseillé de mettre des parenthèses pour chaque condition afin d’éviter les ambiguïtés.
3 [4 , 5 , 6] , Maintenant que les arrays de booléens ont été introduits, nous pouvons définir les masques booléens :
4 [7 , 8 , 9]])
5 >>> l1 , l2 , l3 = a
6 >>> l1 Définition
7 array ([1 , 2 , 3])
8 >>> l2 Les masques booléens sont des arrays de booléens qui sont utilisés en tant qu’« indice » d’un array initial. Cela permet
9 array ([4 , 5 , 6]) de récupérer / modifier une partie de l’array initial.
10 >>> l3
11 array ([7 , 8 , 9])
Par défaut, cela se fait sur les lignes de l’array 2D. Cette fonctionnalité provient à nouveau du fait que pour NumPy a[i] Concrètement, il suffira d’utiliser un array et un opérateur de comparaison entre les crochets qui étaient dédiés à l’indi-
correspond à la ligne d’indice i d’un array 2D. çage :
Pour utiliser l’affectation multiple sur les colonnes, il suffit d’utiliser la transposée a.T : 1 >>> a
1 >>> c1 , c2 , c3 = a . T 2 array ([[1 , 2 , 3] ,
2 >>> c1 3 [4 , 5 , 6] ,
3 array ([1 , 4 , 7]) 4 [7 , 8 , 9]])
4 >>> c2 5 >>> a [ a > 5]
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 155 156 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.1. Module NumPy Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.2. Module Biopython
Nous venons de voir une petite partie du module NumPy mais vous avez pu en constater son extraordinaire puissance. On Traduction en séquence protéique :
pourrait au premier abord être tenté d’abandonner les listes, toutefois elles gardent toute leur importance. Alors quand utiliser 19. https://www.labri.fr/perso/nrougier/from-python-to-numpy/
les listes ou quand utiliser les arrays NumPy ? Voici une liste non exhaustive d’éléments qui peuvent guider votre choix : 20. https://numpy.org/numpy-tutorials/index.html
21. http://biopython.org/
18. https://numpy.org/doc/1.18/reference/maskedarray.html 22. http://biopython.org/DIST/docs/tutorial/Tutorial.html
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 157 158 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.2. Module Biopython Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.3. Module matplotlib
Dans l’annexe A Quelques formats de données rencontrés en biologie, vous trouverez de nombreux exemples d’utilisation
de Biopython pour manipuler des données aux formats FASTA, GenBank et PDB.
Ligne 1. On charge directement le sous-module Entrez. Nous pouvons alors facilement obtenir le titre, le DOI et la date de publication (PubDate) de cet article, ainsi que le journal
Ligne 2. Lors d’une requête sur le site du NCBI, il est important de définir correctement la variable Entrez.email qui (Source) dans lequel il a été publié :
sera transmise au NCBI lors de la requête et qui pourra être utilisée pour vous contacter en cas de difficulté avec le serveur. 1 >>> res_esummary [0][" Title "]
Ligne 3. On lance la requête (transferrin) sur le moteur de recherche pubmed. La requête est stockée dans la variable 2 ' Known and potential roles of transferrin in iron biology . '
>>> res_esummary [0][" DOI "]
req_esearch. 3
4 '10.1007/ s10534 -012 -9520 -3 '
Ligne 4. Le résultat est lu et stocké dans la variable res_esearch. 5 >>> res_esummary [0][" PubDate "]
'2012 Aug '
Sans être un vrai dictionnaire, la variable res_esearch en a cependant plusieurs propriétés. Voici ses clés : 6
7 >>> res_esummary [0][" Source "]
1 >>> res_esearch . keys () 8 ' Biometals '
dict_keys ([ ' Count ' , ' RetMax ' , ' RetStart ' , ' IdList ' , ' TranslationSet ' ,
Enfin, pour récupérer le résumé de la publication précédente, nous allons utiliser la fonction Entrez.efetch() :
2
3 ' TranslationStack ' , ' QueryTranslation '])
1 >>> req_efetch = Entrez . efetch ( db =" pubmed " , id ="22294463" , rettype =" txt ")
La valeur associée à la clé IdList est une liste qui contient les identifiants (PMID) des articles scientifiques associés à la 2 >>> res_efetch = Entrez . read ( req_efetch )
requête (ici transferrin) :
La variable res_efetch est un pseudo-dictionnaire qui contient une pseudo-liste, qui contient un pseudo-dictionnaire,
1 >>> res_esearch [" IdList "]
2 [ '30411489 ' , '30409795 ' , '30405884 ' , '30405827 ' , '30402883 ' , '30401570 ' ,
qui contient. . . Oui, c’est compliqué ! Pour faire court, le résumé peut s’obtenir avec l’instruction :
3 '30399508 ' , '30397276 ' , '30395963 ' , '30394734 ' , '30394728 ' , '30394123 ' , 1 >>> res_efetch [ ' PubmedArticle '][0][ ' MedlineCitation '][ ' Article '] \
4 '30393423 ' , '30392910 ' , '30392664 ' , '30391706 ' , '30391651 ' , '30391537 ' , 2 ... [ ' Abstract '][ ' AbstractText '][0]
5 '30391296 ' , '30390672 '] 3 ' Transferrin is an abundant serum metal - binding protein best known
6 >>> len ( res_esearch [" IdList "]) 4 for its role in iron delivery . The human disease congenital atransf
7 20 5 errinemia and animal models of this disease highlight the essential
6 role of transferrin in ery thropoies is and iron metabolism . Patient
Cette liste ne contient les identifiants que de 20 publications alors que si nous faisons cette même requête directement sur 7 s and mice deficient in transferrin exhibit anemia and a paradoxica
8 l iron overload attributed to deficiency in hepcidin , a peptide hor
le site de PubMed depuis un navigateur web, nous obtenons plus de 33900 résultats. 9 mone synthesized largely by the liver that inhibits dietary iron ab
En réalité, le nombre exact de publications est connu : 10 sorption and macrophage iron efflux . Studies of inherited human dis
11 ease and model organisms indicate that transferrin is an essential
>>> res_esearch [" Count "] 12 regulator of hepcidin expression . In this paper , we review current
literature on transferrin deficiency and present our recent finding
1
'33988 ' 13
s , including potential overlaps between transferrin , iron and manga
2
14
15 nese in the regulation of hepcidin expression . '
Pour ne pas saturer les serveurs du NCBI, seulement 20 PMID sont renvoyés par défaut. Mais vous pouvez augmenter
cette limite en utilisant le paramètre retmax dans la fonction Entrez.esearch(). Ce qui est bien le résumé que nous obtenons sur la figure 17.2.
Nous pouvons maintenant récupérer des informations sur une publication précise en connaissant son PMID. Par exemple,
l’article avec le PMID 22294463 24 dont un aperçu est sur la figure 17.2.
Nous allons pour cela utiliser la fonction Entrez.esummary() 17.3 Module matplotlib
1 >>> req_esummary = Entrez . esummary ( db =" pubmed " , id ="22294463") Le module matplotlib 25 permet de générer des graphiques depuis Python. Il est l’outil complémentaire de NumPy, scipy
2 >>> res_esummary = Entrez . read ( req_esummary )
ou pandas (que l’on verra juste après) lorsqu’on veut faire de l’analyse de données.
La variable res_esummary n’est pas réellement une liste mais en a plusieurs propriétés. Cette pseudo-liste n’a qu’un seul
élément, qui est lui-même un pseudo-dictionnaire dont voici les clés : 17.3.1 Représentation sous forme de points
1 >>> res_esummary [0]. keys ()
2 dict_keys ([ ' Item ' , 'Id ' , ' PubDate ' , ' EPubDate ' , ' Source ' , ' AuthorList ' , Dans cet exemple, nous considérons l’évolution de la concentration d’un produit dans le sang (exprimé en mg/L) en
3 ' LastAuthor ' , ' Title ' , ' Volume ' , ' Issue ' , ' Pages ' , ' LangList ' , fonction du temps (exprimé en heure).
4 ' NlmUniqueID ' , ' ISSN ' , ' ESSN ' , ' PubTypeList ' , ' RecordStatus ' , ' PubStatus ' ,
5 ' ArticleIds ' , 'DOI ' , ' History ' , ' References ' , ' HasAbstract ' , ' PmcRefCount ' , Nous avons les résultats suivants :
6 ' FullJournalName ' , ' ELocationID ' , 'SO '])
23. https://www.ncbi.nlm.nih.gov/pubmed/
24. https://www.ncbi.nlm.nih.gov/pubmed/22294463 25. https://matplotlib.org/
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 159 160 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.3. Module matplotlib Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.3. Module matplotlib
Ligne 5. La fonction scatter() permet de représenter des points sous forme de nuage de points. Les deux premiers
F IGURE 17.3 – Fenêtre interactive de matplotlib.
arguments correspondent aux valeurs en abscisse et en ordonnée des points, fournis sous forme de listes. Des arguments
facultatifs sont ensuite précisés comme le symbole (marker) et la couleur (color).
Temps (h) Concentration (mg/L) Lignes 6 et 7. Les fonctions xlabel() et ylabel() sont utilisées pour donner un nom aux axes.
Ligne 8. La fonction title() définit le titre du graphique.
1 3.5 Ligne 9. Enfin, la fonction show() affiche le graphique généré à l’écran.
2 5.8
3 9.1
4 11.8 17.3.2 Représentation sous forme de courbe
6 17.5 On sait par ailleurs que l’évolution de la concentration du produit en fonction du temps peut-être modélisée par la fonction
7 21.3 f (x) = 2 + 3 × x. Représentons ce modèle avec les points expérimentaux et sauvegardons le graphique obtenu sous forme
9 26.8 d’une image :
1 import numpy as np
2 import matplotlib . pyplot as plt
Nous allons maintenant représenter l’évolution de la concentration en fonction du temps : 3
4 temps = [1 , 2 , 3 , 4 , 6 , 7 , 9]
1 import matplotlib . pyplot as plt
2
5 concentration = [5.5 , 7.2 , 11.8 , 13.6 , 19.1 , 21.7 , 29.4]
3 temps = [1 , 2 , 3 , 4 , 6 , 7 , 9] 6 plt . scatter ( temps , concentration , marker =" o " , color = " blue ")
4 concentration = [5.5 , 7.2 , 11.8 , 13.6 , 19.1 , 21.7 , 29.4] 7 plt . xlabel (" Temps ( h )")
5 plt . scatter ( temps , concentration , marker =" o " , color =" blue ") 8 plt . ylabel (" Concentration ( mg / L )")
6 plt . xlabel (" Temps ( h )") 9 plt . title (" Concentration de produit en fonction du temps ")
7 plt . ylabel (" Concentration ( mg / L )") 10 x = np . linspace ( min ( temps ) , max ( temps ) , 50)
11 y = 2 + 3 * x
8 plt . title (" Concentration de produit en fonction du temps ")
12 plt . plot (x , y , color = ' green ' , ls =" - -")
9 plt . show ()
13 plt . grid ()
14 plt . savefig (" c o n c e n t r a t i o n _ v s _ t e m p s . png " , bbox_inches = ' tight ' , dpi =200)
Vous devriez obtenir une fenêtre graphique interactive qui vous permet de manipuler le graphe (se déplacer, zoomer,
enregistrer comme image, etc.) et qui ressemble à celle de la figure 17.3. Le résultat est représenté sur la figure 17.4.
Revenons maintenant sur le code. Les étapes supplémentaires par rapport au graphique précédent (figure 17.3) sont :
Ligne 1. Tout d’abord, on importe le sous-module pyplot du module matplotlib et on lui donne l’alias plt pour l’utiliser Ligne 1. On charge le module numpy sous le nom np.
plus rapidement ensuite (cet alias est standard, utilisez-la systématiquement). Ligne 10. On crée la variable x avec la fonction linspace() du module NumPy qui renvoie une liste de valeurs réguliè-
Lignes 3 et 4. On définit les variables temps et concentration comme des listes. Les deux listes doivent avoir la même rement espacées entre deux bornes, ici entre le minimum (min(temps)) et le maximum (max(temps)) de la variable temps.
longueur (7 éléments dans le cas présent). Dans notre exemple, nous générons une liste de 50 valeurs. La variable x ainsi créée est du type array.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 161 162 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.3. Module matplotlib Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.4. Module pandas
Lignes 7 et 8. On calcule la distribution des différentes bases dans la séquence. On utilise pour cela la méthode count()
qui renvoie le nombre de fois qu’une chaîne de caractères (les différentes bases) se trouve dans une autre (la séquence).
Ligne 10. On définit la position en abscisse des barres. Dans cet exemple, la variable x vaut array([0, 1, 2, 3]).
Ligne 11. La fonction bar() construit le diagramme en bâtons. Elle prend en argument la position des barres (x) et leurs
hauteurs (distribution).
Ligne 12. La fonction xtics() redéfinit les étiquettes (c’est-à-dire le nom des bases) sur l’axe des abscisses.
Lignes 13 à 15. On définit les légendes des axes et le titre du graphique. On insère un retour à la ligne \n dans le titre pour
qu’il soit réparti sur deux lignes.
Ligne 16. Enfin, on enregistre le graphique généré au format png.
On espère que ces courts exemples vous auront convaincu de l’utilité du module matplotlib. Sachez qu’il peut faire bien
plus, par exemple générer des histogrammes ou toutes sortes de graphiques utiles en analyse de données.
26. https://matplotlib.org/gallery/index.html
On obtient alors le graphique de la figure 17.5.
27. https://www.python-graph-gallery.com/matplotlib/
Prenons le temps d’examiner les différentes étapes du script précédent : 28. https://github.com/matplotlib/cheatsheets
Lignes 4 à 6. On définit les variables sequence, bases et distribution qu’on utilise ensuite. 29. https://pandas.pydata.org/
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 163 164 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.4. Module pandas Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.4. Module pandas
Les étiquettes permettent de modifier et d’ajouter des éléments : 17.4.3 Quelques propriétés
>>> s [" c "] = 300
Les dimensions d’un dataframe sont données par l’attribut .shape :
1
2 >>> s [" z "] = 50
3 >>> s 1 >>> df . shape
4 a 10 (3 , 4)
5 b 20 2
6 c 300
7 d 40 Ici, le dataframe df a 3 lignes et 4 colonnes.
8 z 50 L’attribut .columns renvoie le nom des colonnes et permet aussi de renommer les colonnes d’un dataframe :
9 dtype : int64
1 >>> df . columns
Enfin, on peut filtrer une partie de la series : 2 Index ([ 'a ' , 'b ' , 'c ' , 'd '] , dtype = ' object ')
1 >>> s [s >30] 3 >>> df . columns = [" Paris " , " Lyon " , " Nantes " , " Pau "]
2 c 300 4 >>> df
3 d 40 5 Paris Lyon Nantes Pau
4 z 50 6 chat 10 11 12 13
5 dtype : int64 7 singe 20 21 22 23
8 souris 30 31 32 33
et même combiner plusieurs critères de sélection :
La méthode .head(n) renvoie les n premières lignes du dataframe (par défaut, n vaut 5) :
1 >>> s [( s >20) & (s <100)]
2 d 40 1 >>> df . head (2)
3 z 50 2 Paris Lyon Nantes Pau
4 dtype : int64 3 chat 10 11 12 13
4 singe 20 21 22 23
17.4.2 Dataframes
17.4.4 Sélection
Un autre type d’objet particulièrement intéressant introduit par pandas sont les dataframes. Ceux-ci correspondent à des
tableaux à deux dimensions avec des étiquettes pour nommer les lignes et les colonnes. Les mécanismes de sélection fournis avec pandas sont très puissants. En voici un rapide aperçu :
Ligne 1. Le dataframe est créé avec la fonction DataFrame() à laquelle on fournit plusieurs arguments. L’argument Sélection de lignes
columns indique le nom des colonnes, sous forme d’une liste.
Ligne 2. L’argument index définit le nom des lignes, sous forme de liste. Pour sélectionner une ligne, il faut utiliser l’instruction .loc() et l’étiquette de la ligne :
Lignes 3-5. L’argument data fournit le contenu du dataframe, sous la forme d’une liste de valeurs correspondantes à des 1 >>> df . loc [" singe "]
Paris 20
lignes. Ainsi np.arange(10, 14) qui est équivalent à [10, 11, 12, 13] correspond à la première ligne du dataframe. 2
3 Lyon 21
Notez ici qu’il faut avoir préalablement importer numpy avec l’instruction import numpy as np. 4 Nantes 22
5 Pau 23
Le même dataframe peut aussi être créé à partir des valeurs fournies en colonnes sous la forme d’un dictionnaire : 6 Name : singe , dtype : int64
1 >>> data = {" a ": np . arange (10 , 40 , 10) ,
2 ... " b ": np . arange (11 , 40 , 10) , Ici aussi, on peut sélectionner plusieurs lignes :
... " c ": np . arange (12 , 40 , 10) ,
>>> df . loc [[" singe " , " chat "]]
3
1
4 ... " d ": np . arange (13 , 40 , 10)} 2 Paris Lyon Nantes Pau
5 >>> df = pd . DataFrame ( data ) 3 singe 20 21 22 23
6 >>> df . index = [" chat " , " singe " , " souris "] 4 chat 10 11 12 13
7 >>> df
8 a b c d Enfin, on peut aussi sélectionner des lignes avec l’instruction .iloc et l’indice de la ligne (la première ligne ayant l’indice
9 chat 10 11 12 13
10 singe 20 21 22 23 0) :
11 souris 30 31 32 33
1 >>> df . iloc [1]
Lignes 1-4. Le dictionnaire data contient les données en colonnes. La clé associée à chaque colonne est le nom de la 2 Paris 20
3 Lyon 21
colonne. 4 Nantes 22
Ligne 5. Le dataframe est créé avec la fonction pd.DataFrame() à laquelle on passe data en argument. 5 Pau 23
6 Name : singe , dtype : int64
Ligne 6. On peut définir les étiquettes des lignes de n’importe quel dataframe avec l’attribut df.index.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 165 166 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.4. Module pandas Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.5. Un exemple plus complet
On peut aussi combiner plusieurs conditions avec & pour l’opérateur et : 17.5 Un exemple plus complet
1 >>> df [ ( df [" Pau "] >15) & ( df [" Lyon "] >25) ]
2 Paris Lyon Nantes Pau Pour illustrer les possibilités de pandas, voici un exemple plus complet.
3 souris 30 31 32 33 Le fichier transferrin_report.csv que vous pouvez télécharger ici 31 contient une liste de structures de la transfer-
et | pour l’opérateur ou : rine 32 . Cette protéine est responsable du transport du fer dans l’organisme.
Si vous n’êtes pas familier avec le format de fichier .csv, nous vous conseillons de consulter l’annexe A Quelques formats
1 >>> df [ ( df [" Pau "] >15) | ( df [" Lyon "] >25) ]
2 Paris Lyon Nantes Pau de données rencontrés en biologie.
3 singe 20 21 22 23 Voyons maintenant comment explorer les données contenues dans ce fichier avec pandas.
4 souris 30 31 32 33
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 167 168 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.5. Un exemple plus complet Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.5. Un exemple plus complet
Notre jeu de données contient donc 41 lignes et 4 colonnes. En effet, la colonne PDB ID est maintenant utilisée comme 17.5.3 Statistiques descriptives et table de comptage
index et n’est donc plus prise en compte. Pour les colonnes qui contiennent des données numériques, on peut obtenir rapidement quelques statistiques descriptives
Il est aussi intéressant de savoir de quel type de données est constituée chaque colonne : avec la méthode .describe() :
1 >>> df . dtypes
2 Source object 1 >>> df . describe ()
3 Deposit Date object 2 Length MW
4 Length int64 3 count 41.000000 41.000000
5 MW float64 4 mean 477.341463 52816.090244
6 dtype : object 5 std 175.710217 19486.594012
6 min 304.000000 33548.100000
Les colonnes Length et MW contiennent des valeurs numériques, respectivement des entiers (int64) et des floats (float64). 7 25% 331.000000 36542.300000
50% 337.000000 37229.300000
Le type object est un type par défaut.
8
9 75% 679.000000 75298.500000
La méthode .info() permet d’aller un peu plus loin dans l’exploration du jeu de données en combinant les informations 10 max 696.000000 77067.900000
produites par les propriétés .shape et .dtypes :
On apprend ainsi que la masse moléculaire (colonne MW) a une valeur moyenne de 52816.090244 avec un écart-type de
1 >>> df . info ()
2 < class ' pandas . core . frame . DataFrame ' > 19486.594012 et que la plus petite valeur est 33548.100000 et la plus grande 77067.900000. Pratique !
3 Index : 41 entries , 1 A8E to 6 CTC La colonne Source contient des chaînes de caractères, on peut rapidement déterminer le nombre de protéines pour chaque
4 Data columns ( total 4 columns ):
5 # Column Non - Null Count Dtype organisme :
6 --- ------ - - - - - - - - - - - - - - -----
7 0 Source 41 non - null object 1 >>> df [" Source "]. value_counts ()
8 1 Deposit Date 41 non - null object 2 Homo sapiens 26
9 2 Length 41 non - null int64 3 Gallus gallus 10
10 3 MW 41 non - null float64 4 Anas platyrhynchos 2
11 dtypes : float64 (1) , int64 (1) , object (2) 5 Oryctolagus cuniculus 2
12 memory usage : 1.6+ KB 6 Sus scrofa 1
7 Name : Source , dtype : int64
Avec l’argument memory_usage="deep", cette méthode permet surtout de connaitre avec précision la taille de l’espace
mémoire occupé par le dataframe : Ainsi, 26 protéines sont d’origine humaine (Homo sapiens) et 10 proviennent de la poule (Gallus gallus).
1 >>> df . info ( memory_usage =" deep ")
2 < class ' pandas . core . frame . DataFrame ' >
3 Index : 41 entries , 1 A8E to 6 CTC 17.5.4 Statistiques par groupe
4 Data columns ( total 4 columns ):
5 # Column Non - Null Count Dtype On peut aussi déterminer, pour chaque organisme, la taille et la masse moléculaire moyennes des transferrines :
6 --- ------ - - - - - - - - - - - - - - -----
7 0 Source 41 non - null object 1 >>> df . groupby ([" Source "]). mean ()
8 1 Deposit Date 41 non - null object 2 Length MW
9 2 Length 41 non - null int64 3 Source
10 3 MW 41 non - null float64 4 Anas platyrhynchos 686.000000 75731.800000
11 dtypes : float64 (1) , int64 (1) , object (2) 5 Gallus gallus 509.300000 56324.080000
12 memory usage : 8.6 KB 6 Homo sapiens 439.615385 48663.392308
7 Oryctolagus cuniculus 490.000000 54219.600000
Ici, le dataframe occupe 8,6 ko en mémoire. 8 Sus scrofa 696.000000 77067.900000
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 169 170 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.5. Un exemple plus complet Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.5. Un exemple plus complet
La méthode .groupby() rassemble d’abord les données suivant la colonne Source puis la méthode .mean() calcule la
moyenne pour chaque groupe. F IGURE 17.7 – Masse moléculaire en fonction de la taille (zoom) avec un modèle linaire.
Si on souhaite obtenir deux statistiques (par exemple la valeur minimale et maximale) en une seule fois, il convient alors
d’utiliser la méthode .pivot_table() plus complexe mais aussi beaucoup plus puissante :
>>> plt . clf ()
>>> df . pivot_table ( index =" Source " , values =[" Length " , " MW "] , aggfunc =[ min , max ])
1
1
2 min max 2 >>> plt . scatter ( dfz [" Length "] , dfz [" MW "])
3 Length MW Length MW 3 < matplotlib . collections . Pa thCollec tion object at 0 x7f85bb4852e8 >
4 Source 4 >>> plt . xlabel (" Taille ( nombre d ' acides amin é s )")
5 Anas platyrhynchos 686 75731.8 686 75731.8 5 Text (0.5 , 0 , " Taille ( nombre d ' acides amin é s )")
6 Gallus gallus 328 36105.8 686 75957.1 6 >>> plt . ylabel (" Masse mol é culaire ( Dalton )")
7 Homo sapiens 327 36214.2 691 76250.2 7 Text (0 , 0.5 , ' Masse mol é culaire ( Dalton ) ')
8 Oryctolagus cuniculus 304 33548.1 676 74891.1 8 >>> plt . savefig (" transferrine2 . png ")
9 Sus scrofa 696 77067.9 696 77067.9
L’argument index précise la colonne dont on agrège les données. Ligne 1. L’instruction plt.clf() efface le graphe précédent mais conserve les noms des axes des abscisses et des ordon-
L’argument values indique sur quelles colonnes les statistiques sont calculées. nées.
Enfin, aggfunc liste les statistiques calculées, ici la valeur minimale et maximale.
Le graphique 17.6 (B) obtenu met en évidence une relation linéaire entre le nombre de résidus d’une protéine et sa masse
Notez que les valeurs renvoyées sont d’abord les valeurs minimales pour Length et MW puis les valeurs maximales pour
moléculaire.
Length et MW.
En réalisant une régression linéaire, on détermine les paramètres de la droite qui passent le plus proche possible des points
du graphique.
17.5.5 Analyse de données numériques
1 >>> from scipy . stats import linregress
On peut, sans trop de risque, émettre l’hypothèse que plus il y a d’acides aminés dans la protéine, plus sa masse moléculaire 2 >>> lr = linregress ( dfz [" Length "] , dfz [" MW "])
va être élevée. 3 >>> lr
4 LinregressRes u l t ( slope =116.18244897959184 , intercept = -1871.6131972789153 ,
Pour vérifier cela graphiquement, on représente la masse moléculaire de la protéine en fonction de sa taille (c’est-à-dire 5 rvalue =0.993825553885062 , pvalue = 1 . 6 6 4 9 32 3 7 9 9 3 6 2 9 4 e -22 ,
du nombre d’acides aminés). 6 stderr = 2 . 7 6 5 4 2 3 2 3 9 3 3 6 6 8 5 )
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 171 172 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.5. Un exemple plus complet Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.6. Exercices
En 2001, cinq structures de transferrine ont été déposées dans la PDB. La deuxième « meilleure » année est 2003 avec Lecture des coordonnées
quatre structures. Ouvrez le fichier 1bta_CA.txt avec Python et créez une liste contenant toutes les coordonnées sous forme de floats avec
Toutes ces méthodes, enchaînées les unes à la suite des autres, peuvent vous sembler complexes mais chacune d’elles les fonctions split() et float().
correspond à une étape particulière du traitement des données. L’utilisation des parenthèses (ligne 1, juste avant df["Deposit Affichez à l’écran le nombre total de coordonnées.
Date"] et ligne 5, juste après head()) permet de répartir élégamment cette longue instruction sur plusieurs lignes.
Bien sûr, on aurait pu créer des variables intermédiaires pour chaque étape mais cela aurait été plus lourd :
1 >>> date1 = df [" Deposit Date "]. value_counts ()
Construction de la matrice de coordonnées
2 >>> date2 = date1 . resample (" A ")
3 >>> date3 = date2 . count () En ouvrant dans un éditeur de texte le fichier 1bta.pdb, trouvez le nombre d’acides aminés qui constituent la barstar.
4 >>> date4 = date3 . sort_values ( ascending = False ) Avec la fonction array() du module NumPy, convertissez la liste de coordonnées en array. Avec la fonction reshape()
5 >>> date4 . head ()
6 2001 -12 -31 5 de NumPy, construisez ensuite une matrice à deux dimensions contenant les coordonnées des carbones alpha de la barstar.
7 2003 -12 -31 4 Affichez les dimensions de cette matrice.
8 1998 -12 -31 3
9 1999 -12 -31 3
10 2002 -12 -31 3 33. http://www.rcsb.org/pdb/explore.do?structureId=1BTA
11 Name : Deposit Date , dtype : int64 34. https://files.rcsb.org/download/1BTA.pdb
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 173 174 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.6. Exercices Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.6. Exercices
Calcul de la distance
Créez maintenant une matrice qui contient les coordonnées des n − 1 premiers carbones alpha et une autre qui contient les
coordonnées des n − 1 derniers carbones alpha. Affichez les dimensions des matrices pour vérification.
En utilisant les opérateurs mathématiques habituels (-, +, **2) et les fonctions sqrt() et sum() du module NumPy,
calculez la distance entre les atomes n et n + 1.
Pour chaque atome, affichez le numéro de l’atome et la distance entre carbones alpha consécutifs avec un chiffres après la
virgule. Repérez la valeur surprenante.
À l’aide du module NumPy, on souhaite déterminer quel est le jour de la semaine le plus chaud. Pour cela nous vous
proposons les étapes suivantes :
1. Récupérez le nom des jours de la semaine depuis le fichier et mettez-les dans une liste days.
2. Récupérez les valeurs de températures depuis le fichier et mettez-les dans un array 2D. La fonction np.loadtxt() 36
et son argument usecols vous seront utiles.
3. Parcourez chaque ligne de la matrice, calculez la température moyenne de chaque jour puis stockez-la dans une liste
mean_temps.
4. À l’aide des deux listes days et mean_temps, déterminez et affichez le jour le plus chaud.
17.6.4 Calcul du centre de masse d’une membrane F IGURE 17.8 – Cliché d’une membrane de POPC.
L’image de gauche de la figure 17.8 montre le cliché d’une membrane de POPC (cyan) entourée d’eau (bleu) (coordonnées
trouvées ici 37 ). Les atomes de phosphore des groupes phosphates sont représentés en boule de van der Waals brune. Dans cet 11 [...]
12 # Axis + title .
exercice on cherche à calculer le centre de masse de la membrane, ainsi que le centre de masse (COM) de chaque monocouche 13 ax . set_xlabel (" x ( Å )")
de phosphores. Ces COM sont représentés sous forme de croix dans l’image de droite de la figure 17.8. 14 ax . set_ylabel (" y ( Å )")
Les coordonnées cartésiennes (x, y, z) de chaque phosphore (en Å) sont stockées dans le fichier coors_P.dat 38 , à raison 15 ax . set_zlabel (" z ( Å )")
16 ax . set_title (" Graphe 3 D des phosphores ")
d’un atome par ligne. Nous vous proposons les étapes suivantes pour résoudre cet exercice à l’aide du module NumPy : 17 plt . show ()
— Récupérez les coordonnées des atomes de phosphore depuis le fichier coors_P.dat et stockez-les dans un array 2D
(matrice) coors_P. La dimensionnalité de cette matrice est n × 3, avec n le nombre de phosphores.
— Calculez le z moyen de tous les phosphores (nombre réel) et stockez-le dans la variable mean_z. La méthode .mean() 17.6.5 Années de publication des articles relatifs à la barstar
vous sera utile.
— Avec des masques de booléens, récupérez les coordonnées des phosphores de la monocouche du haut dans un array L’objectif de cet exercice est d’interroger automatiquement la base de données bibliographique PubMed pour déterminer
2D upper. Faites de même avec la monocouche du bas dans un array 2D lower. le nombre d’articles relatifs à la barstar publiés chaque année.
— Calculez le centre de masse COM de la membrane, ainsi que de la monocouche du haut COM_upper et du bas COM_lower. Vous utiliserez les modules Biopython et matplotlib.
Pensez aux méthodes de calcul sur les arrays et l’argument axis.
— Une fois tout cela effectué, créez un graphique 3D pour représenter les différents centres de masse. Vous pourrez Requête avec un mot-clé
utiliser la fonction scatter() du module matplotlib. Pour l’affichage en 3D 39 , voici un squelette de programme :
1 # Init plot . Sur le site de PubMed 40 , cherchez combien d’articles scientifiques sont relatifs à la barstar.
2 from mpl_toolkits . mplot3d import Axes3D Effectuez la même chose avec Python et la méthode Entrez.esearch() de Biopython.
3 import matplotlib . pyplot as plt
4 fig = plt . figure () Choisissez un des PMID renvoyé et vérifiez dans PubMed que l’article associé est bien à propos de la barstar. Pour cela,
5 ax = fig . add_subplot (111 , projection = '3d ') indiquez le PMID choisi dans la barre de recherche de PubMed et cliquez sur Search. Attention, l’association n’est pas toujours
6 [...] évidente. Cherchez éventuellement dans le résumé de l’article si besoin.
7 # X , Y et Z sont des arrays 1 D de n é l é ments ( par exemple X repr é sente tous les x des P de la monocouche upper ).
8 ax . scatter (X , Y , Z , c =" salmon " , marker =" o ") Est-ce que le nombre total d’articles trouvés est cohérent avec celui obtenu sur le site de PubMed ?
9 # x , y , z sont des floats avec les coordonn é es du COM de la upper .
10 ax . scatter (x , y , z , c =" red " , marker =" x ")
Récupération des informations d’une publication
35. https://python.sdv.univ-paris-diderot.fr/data-files/temperatures.dat
36. https://numpy.org/doc/stable/reference/generated/numpy.loadtxt.html Récupérez les informations de la publication dont le PMID est 29701945 41 . Vous utiliserez la méthode Entrez.esummary().
37. https://zenodo.org/record/153944
38. https://python.sdv.univ-paris-diderot.fr/data-files/coors_P.dat 40. https://www.ncbi.nlm.nih.gov/pubmed/
39. https://matplotlib.org/3.2.1/gallery/mplot3d/scatter3d.html 41. https://www.ncbi.nlm.nih.gov/pubmed/29701945
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 175 176 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
17.6. Exercices Chapitre 17. Quelques modules d’intérêt en bioinformatique Chapitre 17. Quelques modules d’intérêt en bioinformatique 17.6. Exercices
Affichez le titre, le DOI, le nom du journal (Source) et la date de publication (PubDate) de cet article. Vérifiez que cela de données rencontrés en biologie.
correspond bien à ce que vous avez lu sur PubMed.
Chargement du jeu de données
Récupération du résumé d’une publication
Téléchargez le fichier people.tsv 42 .
Récupérez le résumé de la publication dont le PMID est 29701945. Vous utiliserez la méthode Entrez.efetch(). Ouvrez ce fichier avec pandas et la fonction .read_csv(). N’oubliez pas de préciser le séparateur par défaut avec l’ar-
Affichez ce résumé. Combien de caractères contient-il ? gument sep="\t". Utilisez également l’argument index_col pour utiliser la colonne name comme index.
Affichez les 6 premières lignes du jeu de données.
Distribution des années de publication des articles relatifs à la barstar Combien de lignes contient le jeu de données ?
En utilisant la méthode Entrez.esearch(), récupérez tous les PMID relatifs à la barstar. Pour cela, pensez à augmenter
Sélections
le paramètre retmax. Vos PMID seront stockés dans la liste pmids sous forme de chaînes de caractères. Vérifiez sur PubMed
que vous avez bien récupéré le bon nombre d’articles. Déterminez la taille de Claire.
En utilisant maintenant la méthode Entrez.esummary() dans une boucle, récupérez la date de publication de chaque Déterminez l’âge de Baptiste.
article. Stockez l’année sous forme d’un nombre entier dans la liste years. Cette étape peut prendre une dizaine de minutes, Affichez, en une seule commande, l’âge de Paul et Bob.
soyez patient. Vous pouvez dans votre boucle afficher un message qui indique où vous en êtes dans la récupération des articles.
À la fin vérifiez que votre liste years contient bien autant d’éléments que la liste pmids. Statistiques descriptives et table de comptage
Calculez maintenant le nombre de publications par année. Vous créerez pour cela un dictionnaire freq qui aura pour clé
les années (oui, une clé de dictionnaire peut aussi être un entier) et pour valeur le nombre de publications associées à une Déterminez la moyenne et la valeur minimale de la taille et l’âge des individus.
année donnée. Comptez ensuite le nombre de personnes de chaque sexe.
Créez une liste x qui contient les clés du dictionnaire freq. Ordonnez les valeurs dans x avec la méthode .sort().
Créez maintenant une seconde liste y qui contient, dans l’ordre, le nombre de publications associées à chaque années. Bien Statistiques par groupe
évidemment, les listes x et y doivent avoir la même taille. Au fait, en quelle année la barstar apparaît pour la première fois
Déterminez, la taille et l’âge moyen chez les hommes et les femmes. Utilisez pour cela la méthode .groupby().
dans une publication scientifique ?
Ensuite, avec le module matplotlib, vous allez pouvoir afficher la distribution des publications en fonction des années :
1 import matplotlib . pyplot as plt
Sélections par filtre
2 plt . bar (x , y )
3 plt . show () Déterminez combien de d’individus mesurent plus de 1,80 m.
Quelle femme a moins de 35 ans ?
Vous pouvez également ajouter un peu de cosmétique et enregistrer le graphique sur votre disque dur :
1 import matplotlib . pyplot as plt
2
Sélections et statistiques
3 plt . bar (x , y )
4 Déterminez l’âge moyen des individus qui mesurent plus de 1,80 m.
5 # red é finition des valeurs affich é es sur l ' axe des ordonn é es Déterminez la taille maximale des femmes qui ont plus de 35 ans.
6 plt . yticks ( list ( range (0 , max ( y ) , 2)))
7
8 # é tiquetage des axes et du graphique
9 plt . xlabel (" Ann é es ")
10 plt . ylabel (" Nombre de publications ")
11 plt . title (" Distribution des publications qui mentionnent la barstar ")
12
13 # enregistrement sur le disque
14 plt . savefig (" d i s t r i b u t i o n _ b a r s t a r _ a n n e e . png " , bbox_inches = ' tight ' , dpi =200)
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 177 178 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
Chapitre 18. Jupyter et ses notebooks 18.2. Lancement de Jupyter et création d’un notebook
Chapitre 18
Les notebooks Jupyter sont des cahiers électroniques qui, dans le même document, peuvent rassembler du texte, des
images, des formules mathématiques et du code informatique exécutable. Ils sont manipulables interactivement dans un navi-
gateur web.
Initialement développés pour les langages de programmation Julia, Python et R (d’où le nom Jupyter), les notebooks
Jupyter supportent près de 40 langages différents.
La cellule est l’élément de base d’un notebook Jupyter. Elle peut contenir du texte formaté au format Markdown ou du
code informatique qui pourra être exécuté.
Voici un exemple de notebook Jupyter (figure 18.1) :
Ce notebook est constitué de cinq cellules : deux avec du texte en Markdown (la première et la dernière) et trois avec du
code Python (notées avec In [ ]).
F IGURE 18.1 – Exemple de notebook Jupyter. Les chiffres entourés désignent les différentes cellules.
18.1 Installation
Avec la distribution Miniconda, les notebooks Jupyter s’installent avec la commande :
1 $ conda install -y jupyterlab
Pour être exact, la commande précédente installe un peu plus que les notebooks Jupyter mais nous verrons cela par la
suite.
Une nouvelle page devrait s’ouvrir dans votre navigateur web et ressembler à la figure 18.2.
Cette interface liste les notebooks Jupyter existants (pour le moment aucun).
Pour créer un notebook, cliquez sur le bouton à droite New puis sélectionnez Python 3. Vous noterez au passage qu’il est
également possible de créer un fichier texte, un répertoire ou bien encore de lancer un shell via un Terminal (voir figure 18.3).
Le notebook fraîchement créé ne contient qu’une cellule vide.
La première chose à faire est de donner un nom à votre notebook en cliquant sur Untitled, à droite du logo de Jupyter. Si
le nom de votre notebook est test alors le fichier test.ipynb sera créé dans le répertoire depuis lequel vous avez lancé Jupyter.
Remarque
L’extension .ipynb est l’extension de fichier des notebooks Jupyter. F IGURE 18.2 – Interface de Jupyter.
Vous pouvez entrer des instructions Python dans la première cellule. Par exemple :
1 a = 2
2 b = 3
3 print ( a + b )
179 180 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
18.2. Lancement de Jupyter et création d’un notebook Chapitre 18. Jupyter et ses notebooks Chapitre 18. Jupyter et ses notebooks 18.3. Le format Markdown
Attention
La possibilité d’exécuter les cellules d’un notebook Jupyter dans un ordre arbitraire peut prêter à confusion, notamment si
vous modifiez la même variable d’une cellule à l’autre.
Nous vous recommandons de régulièrement relancer complètement l’exécution de toutes les cellules de votre notebook,
de la première à la dernière, en cliquant sur le menu Kernel puis Restart & Run All et enfin de valider le message Restart and
Run All Cells.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 181 182 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
18.3. Le format Markdown Chapitre 18. Jupyter et ses notebooks Chapitre 18. Jupyter et ses notebooks 18.4. Des graphiques dans les notebooks
Remarque
Pour quitter l’interface des notebooks Jupyter, il faut, dans le premier onglet qui est apparu, cliquer sur le bouton Quit
(figure 18.2).
Une méthode plus radicale est de revenir sur le shell depuis lequel les notebooks Jupyter ont été lancés puis de presser
deux fois la combinaison de touches Ctrl + C.
F IGURE 18.7 – Notebook avec une cellule ré-exécutée.
1. https://fr.wikipedia.org/wiki/Markdown
2. https://daringfireball.net/projects/markdown/syntax
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 183 184 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
18.4. Des graphiques dans les notebooks Chapitre 18. Jupyter et ses notebooks Chapitre 18. Jupyter et ses notebooks 18.4. Des graphiques dans les notebooks
F IGURE 18.9 – Notebook avec une cellule au format Markdown (après exécution).
F IGURE 18.10 – Incorporation d’un graphique dans un notebook Jupyter.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 185 186 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
18.5. Les magic commands Chapitre 18. Jupyter et ses notebooks Chapitre 18. Jupyter et ses notebooks 18.6. JupyterLab
Remarque
Le lancement de n’importe quelle commande Unix depuis un notebook Jupyter (en précédant cette commande de !) est
une fonctionnalité très puissante.
Pour vous en rendre compte, jetez un œil au notebook 3 produit par les chercheurs Zichen Wang et Avi Ma’ayan qui
reproduit l’analyse complète de données obtenues par séquençage haut débit. Ces analyses ont donné lieu à la publication de F IGURE 18.12 – Magic command %history.
l’article scientifique « An open RNA-Seq data analysis pipeline tutorial with an example of reprocessing data from a recent
Zika virus study 4 » (F1000 Research, 2016).
18.6 JupyterLab
En 2018, le consortium Jupyter a lancé JupyterLab qui est un environnement complet d’analyse. Pour obtenir cette inter-
face, lancez la commande suivante depuis un shell :
1 $ jupyter lab
Une nouvelle page devrait s’ouvrir dans votre navigateur web et vous devriez obtenir une interface similaire à la figure
18.14.
L’interface proposée par JupyterLab est très riche. On peut y organiser un notebook Jupyter « classique » avec une figure
en encart, un shell (voir figure 18.15). . . Les possibilités sont infinies !
3. https://github.com/MaayanLab/Zika-RNAseq-Pipeline/blob/master/Zika.ipynb
4. https://f1000research.com/articles/5-1574/
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 187 188 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
18.6. JupyterLab Chapitre 18. Jupyter et ses notebooks Chapitre 18. Jupyter et ses notebooks 18.6. JupyterLab
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 189 190 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
Chapitre 19. Avoir la classe avec les objets 19.1. Construction d’une classe
Ligne 1. La classe Citron est définie. Pas besoin de parenthèses comme avec les fonctions dans un cas simple comme
La programmation orientée objet (POO) est un concept de programmation très puissant qui permet de structurer ses celui-là (nous verrons d’autres exemples plus loin où elles sont nécessaires).
programmes d’une manière nouvelle. En POO, on définit un « objet » qui peut contenir des « attributs » ainsi que des « Ligne 2. La classe ne contient rien, mais il faut mettre au moins une ligne, on met donc ici le mot-clé Python pass qui ne
méthodes » qui agissent sur lui-même. Par exemple, on définit un objet « citron » qui contient les attributs « saveur » et fait rien (comme dans une fonction qui ne fait rien).
« couleur », ainsi qu’une méthode « presser » permettant d’en extraire le jus. En Python, on utilise une « classe » pour Lignes 4 et 5. Quand on tape le nom de notre classe Citron, Python nous indique que cette classe est connue.
construire un objet. Dans notre exemple, la classe correspondrait au « moule » utilisé pour construire autant d’objets citrons Lignes 6 et 7. Lorsqu’on regarde le type de notre classe Citron, Python nous indique qu’il s’agit d’un type au même titre
que nécessaire. que type(int). Nous avons donc créé un nouveau type !
Ligne 8. On crée une instance de la classe Citron, c’est-à-dire qu’on fabrique un représentant ou objet de la classe Citron
Définition que nous nommons citron1.
Une classe définit des objets qui sont des instances (des représentants) de cette classe. Dans ce chapitre on utilisera les Lignes 9 et 10. Lorsqu’on tape le nom de l’instance citron1, l’interpréteur nous rappelle qu’il s’agit d’un objet de type
mots objet ou instance pour désigner la même chose. Les objets peuvent posséder des attributs (variables associées aux Citron ainsi que son adresse en mémoire.
objets) et des méthodes (qui sont des fonctions associées aux objets et qui peuvent agir sur ces derniers ou encore les utiliser). Il est également possible de vérifier qu’une instance est bien issue d’une classe donnée avec la fonction isinstance() :
1 >>> isinstance ( citron1 , Citron )
2 True
Dans les chapitres précédents, nous avons déjà mentionné qu’en Python tout est objet. Une variable de type int est en fait
un objet de type int, donc construit à partir de la classe int. Pareil pour les float et string. Mais également pour les list, tuple,
dict, etc. Voilà pourquoi nous avons rencontré de nombreuses notations et mots de vocabulaire associés à la POO depuis le 19.1.2 Ajout d’un attribut d’instance
début de ce cours.
La POO permet de rédiger du code plus compact et mieux ré-utilisable. L’utilisation de classes évite l’utilisation de va- Reprenons notre classe Citron et l’instance citron1 créée précédemment. Regardons les attributs et méthodes que cet
riables globales en créant ce qu’on appelle un espace de noms propre à chaque objet permettant d’y encapsuler des attributs objet possède, puis tentons de lui ajouter un attribut :
et des méthodes. De plus, la POO amène de nouveaux concepts tels que le polymorphisme (capacité à redéfinir le comporte- 1 >>> dir ( citron1 )
ment des opérateurs, nous avons déjà vu ces mots vous en souvenez-vous ?), ou bien encore l’héritage (capacité à définir une 2 [ ' __class__ ' , ' __delattr__ ' , ' __dict__ ' , [...] , ' __weakref__ ']
3 >>> citron1 . couleur = " jaune "
classe à partir d’une classe pré-existante et d’y ajouter de nouvelles fonctionnalités). Tous ces concepts seront définis dans ce 4 >>> dir ( citron1 )
chapitre. 5 [ ' __class__ ' , ' __delattr__ ' , ' __dict__ ' , [...] , ' __weakref__ ' , ' couleur ']
6 >>> citron1 . couleur
Malgré tous ces avantages, la POO peut paraître difficile à aborder pour le débutant, spécialement dans la conception 7 ' jaune '
des programmes / algorithmes. Elle nécessite donc la lecture de nombreux exemples, mais surtout beaucoup de pratique.
Bien structurer ses programmes en POO est un véritable art. Il existe même des langages qui formalisent la construction de Lignes 1 et 2. L’objet possède de nombreuses méthodes ou attributs qui commencent et qui se terminent par deux caractères
programmes orientés objets, par exemple le langage UML 1 . underscores. On se souvient que les underscores indiquent qu’il s’agit de méthodes ou attributs destinés au fonctionnement
Dans ce chapitre nous allons vous présenter une introduction à la POO avec Python. Nous vous donnerons tous les éléments interne de l’objet. Nous reviendrons sur certains d’entre-eux dans la suite.
pour démarrer la construction de vos premières classes. Ligne 3. Ici on ajoute un attribut .couleur à l’instance citron1. Notez bien la syntaxe instance.attribut et le point
Après la lecture de ce chapitre, vous verrez d’un autre œil de nombreux exemples évoqués dans les chapitres précédents, qui lie les deux.
et vous comprendrez sans doute de nombreuses subtilités qui avaient pu vous paraître absconses. Lignes 4 à 5. La fonction dir() nous montre que l’attribut .couleur a bien été ajouté à l’objet.
Enfin, il est vivement recommandé de lire ce chapitre avant d’aborder le chapitre 20 Fenêtres graphiques et Tkinter. Lignes 6. La notation instance.attribut donne accès à l’attribut de l’objet.
L’attribut nommé .__dict__ est particulièrement intéressant. Il s’agit d’un dictionnaire qui listera les attributs créés
dynamiquement dans l’instance en cours :
19.1 Construction d’une classe 1 >>> citron1 = Citron ()
2 >>> citron1 . __dict__
Nous allons voir dans cette rubrique comment définir une classe en reprenant notre exemple sur le citron que nous allons 3 {}
4 >>> citron1 . couleur = " jaune "
faire évoluer et complexifier. Attention, certains exemples sont destinés à vous montrer comment les classes fonctionnent 5 >>> citron1 . __dict__
mais leur utilisation n’aurait pas de sens dans un vrai programme. Ainsi, nous vous donnerons plus loin dans ce chapitre les 6 { ' couleur ': ' jaune '}
pratiques recommandées.
L’ajout d’un attribut depuis l’extérieur de la classe (on parle aussi du côté « client ») avec une syntaxe instance.nouvel_attribut
1. https://fr.wikipedia.org/wiki/UML_(informatique) = valeur, créera ce nouvel attribut uniquement pour cette instance :
191 192 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.1. Construction d’une classe Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.1. Construction d’une classe
Vous l’aurez deviné, ce code affichera acide à l’écran. Comme pour les fonctions, une valeur retournée par une méthode
À l’extérieur ou à l’intérieur d’une classe, un attribut de classe peut se retrouver avec une syntaxe NomClasse.attribut : est récupérable dans une variable, ici saveur_citron1.
1 print ( Citron . couleur )
Ce code affiche jaune. L’attribut de classe est aussi visible depuis n’importe quelle instance : 19.1.5 Le constructeur
1 class Citron : Lors de l’instanciation d’un objet à partir d’une classe, il peut être intéressant de lancer des instructions comme par exemple
2 couleur = " jaune "
3 initialiser certaines variables. Pour cela, on ajoute une méthode spéciale nommée .__init__() : cette méthode s’appelle le
4
5 if __name__ == " __main__ ": « constructeur » de la classe. Il s’agit d’une méthode spéciale dont le nom est entouré de doubles underscores : en effet, elle
6 citron1 = Citron () sert au fonctionnement interne de notre classe, et sauf cas extrêmement rare, elle n’est pas supposée être lancée comme une
7 print ( citron1 . couleur ) fonction classique par l’utilisateur de la classe. Ce constructeur est exécuté à chaque instanciation de notre classe, et ne renvoie
8 citron2 = Citron ()
9 print ( citron2 . couleur ) pas de valeur, il ne possède donc pas de return.
L’exécution de ce code affichera :
1 jaune
Remarque
2 jaune Pour les débutants, vous pouvez sauter cette remarque. Certains auteurs préfèrent nommer .__init__() « instantiateur
» ou « initialisateur », pour signifier qu’il existe une autre méthode appelée .__new__() qui participe à la création d’une
instance. Vous n’avez bien sûr pas à retenir ces détails pour continuer la lecture de ce chapitre, retenez simplement que nous
Attention
avons décidé de nommer la méthode .__init__() « constructeur » dans cet ouvrage.
Même si on peut retrouver un attribut de classe avec une syntaxe instance.attribut, un tel attribut ne peut pas être
modifié avec une syntaxe
instance.attribut = nouvelle_valeur (voir la rubrique Différence entre les attributs de classe et d’instance). Pour bien comprendre comment cela fonctionne, nous allons suivre un exemple simple avec le site Python Tutor 2 (déjà
2. http://www.pythontutor.com
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 193 194 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.1. Construction d’une classe Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.1. Construction d’une classe
F IGURE 19.2 – Fonctionnement d’un constructeur (étape 2). F IGURE 19.4 – Fonctionnement d’un constructeur (étape 4).
utilisé dans les chapitres 9 et 12 sur les fonctions). N’hésitez pas à copier/coller ce code dans Python Tutor pour le tester
flèche qui pointe depuis le self vers la variable couleur (qui se trouve elle-même dans l’espace nommé Citron instance).
vous-même :
Si d’autres attributs étaient créés, ils seraient tous répertoriés dans cet espace Citron instance. Vous l’aurez compris,
class Citron :
1
2 def __init__ ( self ):
l’attribut couleur est donc une variable d’instance (voir rubrique Ajout d’un attribut d’instance ci-dessus). La méthode
3 self . couleur = " jaune " .__init__() étant intrinsèquement une fonction, Python Tutor nous rappelle qu’elle ne renvoie rien (d’où le None dans la
4
5
case Return value) une fois son exécution terminée. Et comme avec les fonctions classiques, l’espace mémoire contenant les
6 if __name__ == " __main__ ": variables locales à cette méthode va être détruit une fois son exécution terminée.
7 citron1 = Citron ()
8 print ( citron1 . couleur ) Étape 4 (voir figure 19.4). De retour dans le programme principal, Python Tutor nous indique que citron1 est une
instance de la classe Citron par une flèche pointant vers l’espace Citron instance. Cette instance contient un attribut
Étape 1 (voir figure 19.1). Au départ, Python Tutor nous montre que la classe Citron a été mise en mémoire, elle contient nommé couleur auquel on accéde avec la syntaxe citron1.couleur dans le print(). Notez que si l’instance s’était
pour l’instant la méthode .__init__(). appelée enorme_citron, on aurait utilisé enorme_citron.couleur pour accéder à l’attribut couleur.
Étape 2 (voir figure 19.2). Nous créons ensuite l’instance citron1 à partir de la classe Citron. Notre classe Citron
contenant une méthode .__init__() (le constructeur), celle-ci est immédiatement exécutée au moment de l’instanciation.
Cette méthode prend un argument nommé self : cet argument est obligatoire. Il s’agit en fait d’une référence vers l’instance Conseil
en cours (instance que nous appellerons citron1 de retour dans le programme principal, mais cela serait vrai pour n’importe Dans la mesure du possible, nous vous conseillons de créer tous les attributs d’instance dont vous aurez besoin dans le
quel autre nom d’instance). Python Tutor nous indique cela par une flèche pointant vers un espace nommé Citron instance. constructeur .__init__() plutôt que dans toute autre méthode. Ainsi ils seront visibles dans toute la classe dès l’instancia-
La signification du self est expliquée en détail dans la rubrique suivante. tion.
Étape 3 (voir figure 19.3). Un nouvel attribut est créé s’appelant self.couleur. La chaîne de caractères couleur est ainsi
« accrochée » (grâce au caractère point) à l’instance en cours référencée par le self. Python Tutor nous montre cela par une
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 195 196 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.1. Construction d’une classe Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.1. Construction d’une classe
19.1.6 Passage d’argument(s) à l’instanciation Ligne 2. La méthode .affiche_attributs() montre que le self est bien une référence vers l’instance (ou objet)
citron1 (ou vers n’importe quelle autre instance, par exemple si on crée citron2 = Citron() le self sera une référence
Lors de l’instanciation, il est possible de passer des arguments au constructeur. Comme pour les fonctions, on peut passer vers citron2).
des arguments positionnels ou par mot-clé et en créer autant que l’on veut (voir chapitre 9 Fonctions). Voici un exemple : Ligne 3. La méthode .affiche_attributs() affiche l’attribut .couleur qui avait été créé précédemment dans le
1 class Citron : constructeur. Vous voyez ici l’intérêt principal de l’argument self passé en premier à chaque méthode d’une classe : il «
2 def __init__ ( self , masse , couleur =" jaune "):
3 self . masse = masse accroche » n’importe quel attribut qui sera visible partout dans la classe, y compris dans une méthode où il n’a pas été défini.
4 self . couleur = couleur Lignes 4 à 9. La création de la variable var dans la méthode .__init__() sans l’accrocher à l’objet self fait qu’elle
5
6 n’est plus accessible en dehors de .__init__(). C’est exactement comme pour les fonctions classiques, var est finalement
7 if __name__ == " __main__ ": une variable locale au sein de la méthode .__init__() et n’est plus visible lorsque l’exécution de cette dernière est terminée
8 citron1 = Citron (100)
9 print (" citron1 :" , citron1 . __dict__ ) (cf. chapitres 9 et 12 sur les fonctions). Ainsi, Python renvoie une erreur car var n’existe pas lorsque .affiche_attributs()
10 citron2 = Citron (150 , couleur =" blanc ") est en exécution.
print (" citron2 :" , citron2 . __dict__ )
11
En résumé, le self est nécessaire lorsqu’on a besoin d’accéder à différents attributs dans les différentes méthodes d’une
On a ici un argument positionnel (masse) et un autre par mot-clé (couleur). Le code donnera la sortie suivante : classe. Le self est également nécessaire pour appeler une méthode de la classe depuis une autre méthode :
1 class Citron :
1 citron1 : { ' masse ': 100 , ' couleur ': ' jaune '} 2 def __init__ ( self , couleur =" jaune "):
2 citron2 : { ' masse ': 150 , ' couleur ': ' blanc '} 3 self . couleur = couleur
4 self . affich e _m es sa g e ()
5
6 def affic he _ me ss ag e ( self ):
7 print (" Le citron c ' est trop bon !")
19.1.7 Mieux comprendre le rôle du self 8
9
Cette rubrique va nous aider à mieux comprendre le rôle du self à travers quelques exemples simples. Regardons le code 10 if __name__ == " __main__ ":
citron1 = Citron (" jaune p â le ")
suivant dans lequel nous créons une nouvelle méthode .affiche_attributs() :
11
1 class Citron : Ligne 4. Nous appelons ici la méthode .affiche_message() depuis le constructeur. Pour appeler cette méthode interne
2 def __init__ ( self , couleur =" jaune "): à la classe Citron, on doit utiliser une syntaxe self.méthode(). Le self sert donc pour accéder aux attributs mais aussi
3 self . couleur = couleur
4 var = 2 aux méthodes, ou plus généralement à tout ce qui est accroché à la classe.
5
6 def aff ich e_a t t ri but s ( self ):
Lignes 6 et 7. La méthode .affiche_message() est exécutée. On peut se poser la question Pourquoi passer l’argument
7 print ( self ) self à cette méthode alors qu’on ne s’en sert pas dans celle-ci ?
8 print ( self . couleur )
9 print ( var )
10 Attention
Même si on ne se sert d’aucun attribut dans une méthode, l’argument self (ou quel que soit son nom) est strictement
11
12 if __name__ == " __main__ ":
13 citron1 = Citron () obligatoire. En fait, la notation citron1.affiche_message() est équivalente à Citron.affiche_message(citron1).
citron1 . af fic he _a ttr ibu ts ()
14
Testez les deux pour voir ! Dans cette dernière instruction, on appelle la méthode accrochée à la classe Citron et on lui
Ligne 3. On crée l’attribut couleur que l’on accroche à l’instance avec le self. passe explicitement l’instance citron1 en tant qu’argument. La notation citron1.affiche_message() contient donc en
filigrane un argument, à savoir, la référence vers l’instance citron1 que l’on appelle self au sein de la méthode.
Ligne 4. Nous créons cette fois-ci une variable var sans l’accrocher au self.
Ligne 6. Nous créons une nouvelle méthode dans la classe Citron qui se nomme
.affiche_attributs(). Comme pour le constructeur, cette méthode prend comme premier argument une variable obliga- Conseil : c’est la première notation citron1.affiche_attributs() (ou plus généralement instance.méthode()),
toire, que nous avons à nouveau nommée self. Il s’agit encore une fois d’une référence vers l’objet ou instance créé(e). On plus compacte, qui sera toujours utilisée.
va voir plus bas ce qu’elle contient exactement. Ligne 11. On crée l’instance citron1 en lui passant l’argument "jaune pâle". La variable d’instance couleur prendra
ainsi cette valeur au lieu de celle par défaut ("jaune"). À noter, l’instanciation affichera le message Le citron c'est trop
Attention bon ! puisque la méthode .affiche_attributs() est appelée dans le constructeur .__init__().
On peut appeler cette référence comme on veut, toutefois nous vous conseillons vivement de l’appeler self car c’est une Afin de bien comprendre les différentes étapes des codes de cette rubrique, nous vous conseillons de les retester de votre
convention générale en Python. Ainsi, quelqu’un qui lira votre code comprendra immédiatement de quoi il s’agit. côté dans Python Tutor.
Ligne 7. Cette ligne va afficher le contenu de la variable self. 19.1.8 Différence entre les attributs de classe et d’instance
Lignes 8 et 9. On souhaite que notre méthode .affiche_attributs() affiche ensuite l’attribut de classe .couleur ainsi
que la variable var créée dans le constructeur .__init__(). On a vu ci-dessus comment créer un attribut de classe, il suffit de créer une variable au sein de la classe (en dehors de toute
méthode). En général, les attributs de classe contiennent des propriétés générales à la classe puisqu’ils vont prendre la même
L’exécution de ce code donnera :
valeur quelle que soit l’instance.
1 $ python classe_ex emple 1 . py Au contraire, les attributs d’instance sont spécifiques à chaque instance. Pour en créer, on a vu qu’il suffisait de les
2 < __main__ . Citron object at 0 x7f4e5fb71438 >
3 jaune initialiser dans la méthode .__init__() en utilisant une syntaxe self.nouvel_attribut = valeur. On a vu aussi dans
4 Traceback ( most recent call last ): la rubrique Ajout d’un attribut d’instance que l’on pouvait ajouter un attribut d’instance de l’extérieur avec une syntaxe
5 File " classe _exemp le1 . py " , line 14 , in < module >
6 citron1 . af fic he _a ttr ibu ts () instance.nouvel_attribut = valeur .
7 File " classe _exemp le1 . py " , line 9 , in af fic he_a ttr ibu ts
8 print ( var )
Bien que les deux types d’attributs soient fondamentalement différents au niveau de leur finalité, il existe des similitudes
9 NameError : name 'var ' is not defined lorsqu’on veut accéder à leur valeur. Le code suivant illustre cela :
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 197 198 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.1. Construction d’une classe Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.1. Construction d’une classe
3
4 def __init__ ( self , couleur =" jaune "):
5 self . couleur = couleur # attribut d ' instance
6
7 def aff ich e _ a t t r i b u t s ( self ):
8 print ( f " attribut de classe : { self . saveur }")
9 print ( f " attribut d ' instance : { self . couleur }")
10
11
12 if __name__ == " __main__ ":
13 citron1 = Citron ()
14 citron1 . a f f i c h e _ a t t r i b u t s ()
En résumé, qu’on ait des attributs de classe ou d’instance, on peut accéder à eux de l’extérieur par instance.attribut
et de l’intérieur par self.attribut.
Qu’en est-il de la manière de modifier ces deux types d’attributs ? Les attributs d’instance peuvent se modifier sans pro-
blème de l’extérieur avec une syntaxe instance.attribut_d_instance = nouvelle_valeur et de l’intérieur avec une
syntaxe self.attribut_d_instance = nouvelle_valeur. Ce n’est pas du tout le cas avec les attributs de classe.
Attention
Les attributs de classe ne peuvent pas être modifiés ni à l’extérieur d’une classe via une syntaxe instance.attribut_de_classe
F IGURE 19.5 – Illustration de la signification des attributs de classe et d’instance avec Python Tutor. = nouvelle_valeur, ni à l’intérieur d’une classe via une syntaxe self.attribut_de_classe = nouvelle_valeur.
Puisqu’ils sont destinés à être identiques pour toutes les instances, cela est logique de ne pas pouvoir les modifier via une
instance. Les attributs de classe Python ressemblent en quelque sorte aux attributs statiques du C++.
1 class Citron :
2 forme = " ellipso ï de " # attribut de classe
3 saveur = " acide " # attribut de classe
4 Regardons l’exemple suivant illustrant cela :
5 def __init__ ( self , couleur =" jaune " , taille =" standard " , masse =0):
6 self . couleur = couleur # attribut d ' instance 1 class Citron :
7 self . taille = taille # attribut d ' instance 2 saveur = " acide "
self . masse = masse # attribut d ' instance ( masse en gramme )
3
8
4 if __name__ == " __main__ ":
9
citron1 = Citron ()
def augmente_masse ( self , valeur ):
5
10
11 self . masse += valeur 6 print ( citron1 . saveur )
12
7 citron1 . saveur = " sucr é e "
13 8 print ( citron1 . saveur ) # on regarde ici avec Python Tutor
14 if __name__ == " __main__ ": 9 del citron1 . saveur
15 citron1 = Citron () 10 print ( citron1 . saveur ) # on regarde ici avec Python Tutor
16 print (" Attributs de classe :" , citron1 . forme , citron1 . saveur ) 11 del citron1 . saveur
17 print (" Attributs d ' instance :" , citron1 . taille , citron1 . couleur ,
18 citron1 . masse ) À la ligne 7, on pourrait penser qu’on modifie l’attribut de classe saveur avec une syntaxe instance.attribut_de_classe
19 citron1 . augmente_masse (100) = nouvelle_valeur. Que se passe-t-il exactement ? La figure 19.7 nous montre l’état des variables grâce au site Python Tu-
print (" Attributs d ' instance :" , citron1 . taille , citron1 . couleur ,
20
21 citron1 . masse )
tor. Celui-ci indique que la ligne 7 a en fait créé un nouvel attribut d’instance citron1.saveur (contenant la valeur sucrée)
qui est bien distinct de l’attribut de classe auquel on accédait avant par le même nom ! Tout ceci est dû à la manière dont Python
Lignes 2 et 3. Nous créons deux variables de classe qui seront communes à toutes les instances (disons qu’un citron sera gère les espaces de noms (voir rubrique Espaces de noms). Dans ce cas, l’attribut d’instance est prioritaire sur l’attribut de
toujours ellipsoïde et acide !). classe.
Lignes 6 à 8. Nous créons trois variables d’instance qui seront spécifiques à chaque instance (disons que la taille, la couleur À la ligne 9, on détruit finalement l’attribut d’instance citron1.saveur qui contenait la valeur sucrée. Python Tutor
et la masse d’un citron peuvent varier !), avec des valeurs par défaut. nous montre que citron1.saveur n’existe pas dans l’espace Citron instance qui est vide ; ainsi, Python utilisera l’attribut
Lignes 10 et 11. On crée une nouvelle méthode .augmente_masse() qui augmente l’attribut d’instance .masse. de classe .saveur qui contient toujours la valeur acide (cf. figure 19.7).
Ligne 14 à 21. Dans le programme principal, on instancie la classe Citron sans passer d’argument (les valeurs par défaut La ligne 11 va tenter de détruire l’attribut de classe .saveur. Toutefois, Python interdit cela, ainsi l’erreur suivante sera
"jaune", "standard" et 0 seront donc prises), puis on imprime les attributs. générée :
La figure 19.5 montre l’état des variables après avoir exécuté ce code grâce au site Python Tutor 3 . 1 Traceback ( most recent call last ):
Python Tutor montre bien la différence entre les variables de classe forme et saveur qui apparaissent directement dans 2 File "./ test . py " , line 10 , in < module >
les attributs de la classe Citron lors de sa définition et les trois variables d’instance couleur, taille et masse qui sont liées 3 del ( citron1 . saveur )
AttributeErro r : saveur
à l’instance citron1. Pour autant, on voit dans la dernière instruction print() qu’on peut accéder de la même manière aux
4
variables de classe ou d’instance, lorsqu’on est à l’extérieur, avec une syntaxe instance.attribut. En fait, la seule manière de modifier un attribut de classe est d’utiliser une syntaxe
Au sein des méthodes, on accède également de la même manière aux attributs de classe ou d’instance, avec une syntaxe NomClasse.attribut_de_classe = nouvelle_valeur,
self.attribut : dans l’exemple ci-dessus cela aurait été Citron.saveur = "sucrée". De même, pour sa destruction, il faudra utiliser la
1 class Citron : même syntaxe : del Citron.saveur.
2 saveur = " acide " # attribut de classe
3. http://www.pythontutor.com Conseil
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 199 200 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.1. Construction d’une classe Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.2. Espace de noms
Même si on peut modifier un attribut de classe, nous vous déconseillons de le faire. Une utilité des attributs de classe
est par exemple de définir des constantes (mathématique ou autre), donc cela n’a pas de sens de vouloir les modifier ! Il est
également déconseillé de créer des attributs de classe avec des objets modifiables comme des listes et des dictionnaires, cela
peut avoir des effets désastreux non désirés. Nous verrons plus bas un exemple concret d’attribut de classe qui est très utile, à
savoir le concept d’objet de type property.
Si vous souhaitez avoir des attributs modifiables dans votre classe, créez plutôt des attributs d’instance dans le .__init__().
Définition
Dans la documentation officielle 4 , un espace de noms est défini comme suit : « a namespace is a mapping from names to
objects ». Un espace de noms, c’est finalement une correspondance entre des noms et des objets. Un espace de noms peut être
vu aussi comme une capsule dans laquelle on trouve des noms d’objets. Par exemple, le programme principal ou une fonction
représentent chacun un espace de noms, un module aussi, et bien sûr une classe ou l’instance d’une classe également.
F IGURE 19.6 – Illustration avec Python Tutor de la non destruction d’un attribut de classe (étape 1). Différents espaces de noms peuvent contenir des objets de même nom sans que cela ne pose de problème. Parce qu’ils sont
chacun dans un espace différent, ils peuvent cohabiter sans risque d’écrasement de l’un par l’autre. Par exemple, à chaque
fois que l’on appelle une fonction, un espace de noms est créé pour cette fonction. Python Tutor nous montre cet espace
sous la forme d’une zone dédiée (voir les chapitres 9 et 12 sur les fonctions). Si cette fonction appelle une autre fonction, un
nouvel espace est créé, bien distinct de la fonction appelante (ce nouvel espace peut donc contenir un objet de même nom).
En définitive, ce qui va compter, c’est de savoir quelles règles Python va utiliser pour chercher dans les différents espaces de
noms pour finalement accéder à un objet.
Nous allons dans cette rubrique refaire le point sur ce que l’on a appris dans cet ouvrage sur les espaces de noms en Python,
puis se pencher sur les spécificités de ce concept dans les classes.
4. https://docs.python.org/fr/3/tutorial/classes.html#python-scopes-and-namespaces
5. https://docs.python.org/fr/3/library/functions.html%20comme%20par%20exemple%20%60print()%60
6. https://docs.python.org/fr/3/library/constants.html
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 201 202 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.2. Espace de noms Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.2. Espace de noms
11 self.couleur. À l’extérieur, on utilisera instance.saveur et instance.couleur. Il n’y a donc aucun risque de confu-
12 print (" Dans prog principal i :" , i ) sion possible avec les variables globales saveur et couleur, on accède à chaque variable de la classe avec un nom distinct
13 print (" Dans prog principal j :" , j )
(qu’on soit à l’intérieur ou à l’extérieur de la classe).
Le module mod.py contient les instructions suivantes : Ceci est également vrai pour les méthodes. Si par exemple, on a une méthode avec un certain nom, et une fonction du
1 def fct (): module principal avec le même nom, regardons ce qui se passe :
2 i = -27478524 1 class Citron :
3 print (" Dans module , i local :" , i ) 2 def __init__ ( self ):
4
3 self . couleur = " jaune "
5
4 self . aff iche_cou cou ()
6 def fct2 (): 5 affic he_couco u ()
7 print (" Dans module , j global :" , j ) 6
8
9
7 def affiche_ coucou ( self ):
10 i = 3.14 8 print (" Coucou interne !")
11 j = -76 9
10
def affiche_coucou ():
L’exécution de test_var_module.py donnera : 11
12 print (" Coucou externe ")
1 $ python ./ test_v ar_mo dule . py 13
Les deux variables globales saveur et couleur du programme principal ne peuvent pas être confondues avec les va-
riables d’instance portant le même nom. Au sein de la classe, on utilisera pour récupérer ces dernières self.saveur et 7. https://docs.python.org/3/tutorial/classes.html#python-scopes-and-namespaces
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 203 204 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.3. Polymorphisme Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.3. Polymorphisme
19.3 Polymorphisme 13 return ( f " Votre citron est de couleur { self . couleur } "
14 f " et de taille { self . taille }")
15
Nous allons voir maintenant des propriétés très importantes des classes en Python, le polymorphisme dans cette rubrique 16
et l’héritage dans la suivante. Ces deux concepts donnent un surplus de puissance à la POO par rapport à la programmation 17 if __name__ == " __main__ ":
18 citron1 = CitronBasique ()
classique. 19 print ( citron1 )
Commençons par le polymorphisme. Dans la vie, celui-ci évoque la capacité à prendre plusieurs apparences, qu’en est-il 20 citron2 = CitronCool (" jaune fonc é e " , " minuscule ")
21 print ( citron2 )
en programmation ?
Lignes 1 à 4. Création d’une classe CitronBasique dans laquelle il n’y a qu’un constructeur.
Définition Lignes 7 à 14. Création d’une classe CitronCool où nous avons ajouté la nouvelle méthode .__str__(). Cette dernière
En programmation, le polymorphisme est la capacité d’une fonction (ou méthode) à se comporter différemment en fonction renvoie une chaîne de caractères contenant la description de l’instance.
de l’objet qui lui est passé. Une fonction donnée peut donc avoir plusieurs définitions. Lignes 18 à 21. On crée une instance de chaque classe, et on utilise la fonction print() pour voir leur contenu.
L’exécution de ce code affichera la sortie suivante :
1 < __main__ . CitronBasique object at 0 x7ffe23e717b8 >
Prenons un exemple concret de polymorphisme : la fonction Python sorted() va trier par ordre ASCII si l’argument est 2 Votre citron est de couleur jaune fonc é e et de taille minuscule 8 -)
une chaîne de caractères, et elle va trier par ordre croissant lorsque l’argument est une liste d’entiers : L’utilisation de la fonction print() sur l’instance citron1 construite à partir de la classe CitronBasique affiche le
1 >>> sorted (" citron ") message abscons que nous avons déjà croisé. Par contre, pour l’instance citron2 de la classe CitronCool, le texte correspond
2 [ 'c ' , 'i ' , 'n ' , 'o ' , 'r ' , 't '] à celui retourné par la méthode magique .__str__(). Nous avons donc redéfini comment la fonction print() se comportait
>>> sorted ([1 , -67 , 42 , 0 , 81])
3
4 [ -67 , 0 , 1 , 42 , 81]
avec une instance de la classe CitronCool. Notez que str(citron2) donnerait le même message que print(citron2).
Ce mécanisme pourra être reproduit avec de très nombreux opérateurs et fonctions de bases de Python. En effet, il existe
Le polymorphisme est intimement lié au concept de redéfinition des opérateurs que nous avons déjà croisé à plusieurs une multitude de méthodes magiques, en voici quelques unes :
reprises dans ce livre. — .__repr__() : redéfinit le message obtenu lorsqu’on tape le nom de l’instance dans l’interpréteur ;
— .__add__() : redéfinit le comportement de l’opérateur + ;
Définition — .__mul__() : redéfinit le comportement de l’opérateur * ;
La redéfinition des opérateurs est la capacité à redéfinir le comportement d’un opérateur en fonction des opérandes utilisées — .__del__() : redéfinit le comportement de la fonction del.
(on rappelle dans l’expression 1 + 1, + est l’opérateur d’addition et les deux 1 sont les opérandes). Si on conçoit une classe produisant des objets séquentiels (comme des listes ou des tuples), il existe des méthodes magiques
telles que :
— .__len__() : redéfinit le comportement de la fonction len() ;
Un exemple classique de redéfinition des opérateurs concerne l’opérateur +. Si les opérandes sont de type numérique, il — .__getitem__() : redéfinit le comportement pour récupérer un élément ;
fait une addition, si elles sont des chaînes de caractère il fait une concaténation : — .__getslice__() : redéfinit le comportement avec les tranches.
1 >>> 2 + 2 Certaines méthodes magiques font des choses assez impressionnantes. Par exemple, la méthode .__call__() crée des
2 4
3 >>> " ti " + " ti " instances que l’on peut appeler comme des fonctions ! Dans cet exemple, nous allons vous montrer que l’on peut ainsi créer
4 ' titi ' un moyen inattendu pour mettre à jour des attributs d’instance :
1 class Citronnier :
Nous verrons dans la rubrique suivante sur l’héritage qu’il est également possible de redéfinir des méthodes d’une classe, 2 def __init__ ( self , nb_citrons , age ):
c’est-à-dire leur donner une nouvelle définition. 3 self . nb_citrons , self . age = nb_citrons , age
4
Comment Python permet-il ces prouesses que sont le polymorphisme et la redéfinition des opérateurs ? Et bien, il utilise 5 def __call__ ( self , nb_citrons , age ):
des méthodes dites magiques. 6 self . nb_citrons , self . age = nb_citrons , age
7
8 def __str__ ( self ):
Définition 9 return ( f " Ce citronnier a { self . age } ans "
10 f " et { self . nb_citrons } citrons ")
Une méthode magique (magic method) est une méthode spéciale dont le nom est entouré de double underscores. Par 11
exemple, la méthode .__init__() est une méthode magique. Ces méthodes sont, la plupart du temps, destinées au fonc- 12
13 if __name__ == " __main__ ":
tionnement interne de la classe. Nombre d’entre elles sont destinées à changer le comportement de fonctions ou opérateurs 14 citronnier1 = Citronnier (10 , 3)
internes à Python avec les instances d’une classe que l’on a créée. 15 print ( citronnier1 )
16 citronnier1 (30 , 4)
17 print ( citronnier1 )
Nous allons prendre un exemple concret. Imaginons que suite à la création d’une classe, nous souhaitions que Python À la ligne 16, on utilise une notation instance(arg1, arg2), ce qui va automatiquement appeler la méthode magique
affiche un message personnalisé lors de l’utilisation de la fonction print() avec une instance de cette classe. La méthode ma- .__call__() qui mettra à jour les deux attributs d’instance nbcitrons et age (lignes 5 et 6). Ce code affichera la sortie
gique qui permettra cela est nommée .__str__() : elle redéfinit le comportement d’une instance avec la fonction print(). suivante :
1 class CitronBasique : 1 Ce citronnier a 3 ans et 10 citrons
Ce citronnier a 4 ans et 30 citrons
def __init__ ( self , couleur =" jaune " , taille =" standard "):
2
2
3 self . couleur = " jaune "
4 self . taille = " standard "
5
6
Pour aller plus loin
7 class CitronCool : — Nous vous avons montré l’idée qu’il y avait derrière le polymorphisme, et avec cela vous avez assez pour vous jeter
8 def __init__ ( self , couleur =" jaune " , taille =" standard "): à l’eau et commencer à construire vos propres classes. L’apprentissage de toutes les méthodes magiques va bien sûr
9 self . couleur = couleur
10 self . taille = taille au-delà du présent ouvrage. Toutefois, si vous souhaitez aller plus loin, nous vous conseillons la page de Rafe Kettler 8
11
12 def __str__ ( self ): 8. https://rszalski.github.io/magicmethods
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 205 206 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.4. Héritage Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.4. Héritage
qui est particulièrement complète et très bien faite. Si une méthode de la classe fille possède le même nom que celle de la classe mère, c’est la première qui prend la prio-
rité. Dans ce cas, on dit que la méthode est redéfinie (en anglais on parle de method overriding), tout comme on parlait de
redéfinition des opérateurs un peu plus haut. C’est le même mécanisme, car la redéfinition des opérateurs revient finalement à
redéfinir une méthode magique (comme par exemple la méthode .__add__() pour l’opérateur +).
Voyons un exemple :
19.4 Héritage
1 class Mere :
2 def bonjour ( self ):
19.4.1 Prise en main 3 return " Vous avez le bonjour de la classe m è re !"
4
L’héritage peut évoquer la capacité qu’ont nos parents à nous transmettre certains traits physiques ou de caractère (ne 5
6 class Fille2 ( Mere ):
dit-on pas, j’ai hérité ceci ou cela de ma mère ou de mon père ?). Qu’en est-il en programmation ? 7 def bonjour ( self ):
8 return " Vous avez le bonjour de la classe fille !"
9
Définition 10
11 if __name__ == " __main__ ":
En programmation, l’héritage est la capacité d’une classe d’hériter des propriétés d’une classe pré-existante. On parle de 12 fille = Fille2 ()
classe mère et de classe fille. En Python, l’héritage peut être multiple lorsqu’une classe fille hérite de plusieurs classes mères. 13 print ( fille . bonjour ())
Ce code va afficher Vous avez le bonjour de la classe fille !. La méthode .bonjour() de la classe fille a
En Python, lorsque l’on veut créer une classe héritant d’une autre classe, on ajoutera après le nom de la classe fille le nom donc pris la priorité sur celle de la classe mère. Ce comportement provient de la gestion des espaces de noms par Python, il
de la ou des classe(s) mère(s) entre parenthèses : est traité en détail dans la rubrique suivante.
1 class Mere1 :
2 # contenu de la classe m è re 1
3
Remarque
4 À ce point, nous pouvons faire une note de sémantique importante. Python utilise le mécanisme de redéfinition de méthode
5 class Mere2 :
6 # contenu de la classe m è re 2 (method overriding), c’est-à-dire qu’on redéfinit une méthode héritée d’une classe mère. Il ne faut pas confondre cela avec la
7
8
surcharge de fonction (function overloading) qui désigne le fait d’avoir plusieurs définitions d’une fonction selon le nombres
9 class Fille1 ( Mere1 ): d’arguments et/ou leur type (la surcharge n’est pas supportée par Python contrairement à d’autres langages orientés objet).
10 # contenu de la classe fille 1
11
12
13 class Fille2 ( Mere1 , Mere2 ):
14 # contenu de la classe fille 2
19.4.2 Ordre de résolution des noms
Dans cet exemple, la classe Fille1 hérite de la classe Mere1 et la classe Fille2 hérite des deux classes Mere1 et Mere2.
Dans le cas de la classe Fille2, on parle d’héritage multiple. Voyons maintenant un exemple concret : Vous l’avez compris, il y aura un ordre pour la résolution des noms d’attributs ou de méthodes en fonction du ou des
1 class Mere : héritage(s) de notre classe (à nouveau, cela provient de la manière dont Python gère les espaces de noms). Prenons l’exemple
2 def bonjour ( self ): d’une classe déclarée comme suit class Fille(Mere1, Mere2):. Si on invoque un attribut ou une méthode sur une instance
3 return " Vous avez le bonjour de la classe m è re !"
4 de cette classe, Python cherchera d’abord dans la classe Fille. S’il ne trouve pas, il cherchera ensuite dans la première classe
5
6 class Fille ( Mere ):
mère (Mere1 dans notre exemple). S’il ne trouve pas, il cherchera dans les ancêtres de cette première mère (si elle en a), et
7 def salut ( self ): ce en remontant la filiation (d’abord la grand-mère, puis l’arrière grand-mère, etc). S’il n’a toujours pas trouvé, il cherchera
8 return " Un salut de la classe fille !" dans la deuxième classe mère (Mere2 dans notre exemple) puis dans tous ses ancêtres. Et ainsi de suite, s’il y a plus de deux
9
10 classes mères. Bien sûr, si aucun attribut ou méthode n’est trouvé, Python renverra une erreur.
11 if __name__ == " __main__ ":
12 fille = Fille ()
Il est en général possible d’avoir des informations sur l’ordre de résolution des méthodes d’une classe en évoquant la
13 print ( fille . salut ()) commande help() sur celle-ci ou une de ses instances. Par exemple, nous verrons dans le chapitre suivant le module Tkinter,
14 print ( fille . bonjour ()) imaginons que nous créions une instance de la classe principale du module Tkinter nommée Tk :
Lignes 1 à 3. On définit une classe Mere avec une méthode .bonjour(). 1 >>> import tkinter as tk
Lignes 6 à 8. On définit une classe Fille qui hérite de la classe Mere. Cette classe fille contient une nouvelle méthode 2 >>> racine = tk . Tk ()
.salut(). En invoquant la commande help(racine), l’interpréteur nous montre :
Lignes 12 à 14. Après instanciation de la classe Fille, on utilise la méthode .salut(), puis la méthode .bonjour() 1 Help on class Tk in module tkinter :
héritée de la classe mère. 2
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 207 208 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.4. Héritage Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.4. Héritage
1 >>> class Citron : Lignes 1 à 9. On crée la classe Fruit avec son constructeur qui initialisera tous les attributs d’instance décrivant le fruit.
2 ... pass Lignes 11 à 17. Création d’une méthode .affiche_conseil() qui retourne une chaîne contenant le type de fruit, les
3 ...
4 >>> c = Citron () attributs d’instance du fruit, et un conseil de consommation.
5 >>> dir ( c ) Lignes 20 à 29. Création de la classe Citron qui hérite de la classe Fruit. Le constructeur de Citron prend les mêmes
[ ' __class__ ' , ' __delattr__ ' , ' __dict__ ' , ' __dir__ ' , ' __doc__ ' , ' __eq__ ' ,
arguments que ceux du constructeur de Fruit. La ligne 24 est une étape importante que nous n’avons encore jamais vue : l’ins-
6
7 ' __format__ ' , ' __ge__ ' , ' __getattribute__ ' , ' __gt__ ' , ' __hash__ ' ,
8 ' __init__ ' , ' __le__ ' , ' __lt__ ' , ' __module__ ' , ' __ne__ ' , ' __new__ ' , truction Fruit.__init__() est un appel au constructeur de la classe mère (cf. explications plus bas). Notez bien que le pre-
9 ' __reduce__ ' , ' __reduce_ex__ ' , ' __repr__ ' , ' __setattr__ ' , ' __sizeof__ ' ,
10 ' __str__ ' , ' __subclasshook__ ' , ' __weakref__ '] mier argument passé au constructeur de la classe mère sera systématiquement l’instance en cours self. Le print() en lignes
11 >>> o = object () 26-29 illustre qu’après l’appel du constructeur de la classe mère tous les attributs d’instance (self.taille, self.poids,
12 >>> dir ( o )
13 [ ' __class__ ' , ' __delattr__ ' , ' __dir__ ' , ' __doc__ ' , ' __eq__ ' , ' __format__ ' ,
etc.) ont bel et bien été créés.
14 ' __ge__ ' , ' __getattribute__ ' , ' __gt__ ' , ' __hash__ ' , ' __init__ ' , ' __le__ ' , Lignes 31 à 36. On définit la méthode .__str__() qui va modifier le comportement de notre classe avec print(). Celle-
' __lt__ ' , ' __ne__ ' , ' __new__ ' , ' __reduce__ ' , ' __reduce_ex__ ' , ' __repr__ ' ,
15
16 ' __setattr__ ' , ' __sizeof__ ' , ' __str__ ' , ' __subclasshook__ ']
ci fait également appel à une méthode hértitée de la classe mère nommée .affiche_conseil(). Comme on a l’a héritée,
elle est directement accessible avec un self.méthode() (et de l’extérieur ce serait instance.méthode()).
La quasi-totalité des attributs / méthodes de base de la classe Citron sont donc hérités de la classe object. Par exemple, Lignes 39 à 43. Dans le programme principal, on instancie un objet Citron, puis on utilise print() sur l’instance.
lorsqu’on instancie un objet Citron c = Citron(), Python utilisera la méthode .__init__() héritée de la classe object L’exécution de ce code affichera la sortie suivante :
(puisque nous ne l’avons pas définie dans la classe Citron). 1 (1) Je rentre dans le constructeur de Citron , et je vais appeler
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 209 210 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.4. Héritage Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.5. Accès et modifications des attributs depuis l’extérieur
2 le constructeur de la classe m è re Fruit ! Cet exemple illuste la puissance de l’héritage et du polymorphisme et la facilité avec laquelle on les utilise en Python.
3 (2) Je suis dans le constructeur de la classe Fruit Pour chaque fruit, on utilise la méthode
4 Je viens de cr é er self . taille , self . masse , self . saveur et self . forme
5 (3) J ' ai fini dans le constructeur de Citron , les attributs sont : .affiche_conseil() définie dans la classe mère sans avoir à la réécrire. Bien sûr cet exemple reste simpliste et n’est qu’une
6 self . taille : petite , self . masse : 50 « mise en bouche ». Vous verrez des exemples concrets de la puissance de l’héritage dans le chapitre 20 Fenêtres graphiques
7 self . saveur : acide , self . forme : ellipso ï de
8 et Tkinter ainsi que dans les exercices du présent chapitre. Avec le module Tkinter, chaque objet graphique (bouton, zone de
9 (1) Je rentre dans la m é thode . __str__ () de la classe Citron texte, etc.) est en fait une classe. On peut ainsi créer de nouvelles classes héritant des classes Tkinter afin de personnaliser
10 Je vais lancer la m é thode . affiche_conseil () h é rit é e de la classe Fruit
11 (2) Je suis dans la m é thode . affiche_conseil () de la classe Fruit chaque objet graphique.
12
13 Instance Citron
14 taille : petite , masse : 50 Pour aller plus loin
15 saveur : acide , forme : ellipso ï de
16 conseil : Bon en tarte : - p ! À ce stade, nous pouvons émettre deux remarques :
L’héritage et le polymorphisme donnent toute la puissance à la POO. Toutefois, concevoir ses classes sur un projet,
Prenez bien le temps de suivre ce code pas à pas pour bien en comprendre toutes les étapes. surtout au début de celui-ci, n’est pas chose aisée. Nous vous conseillons de lire d’autres ressources et de vous entraîner
Vous pourrez vous poser la question « Pourquoi utilise-t-on en ligne 24 la syntaxe Fruit.__init__() ? ». Cette syntaxe sur un maximum d’exemples. Si vous souhaitez allez plus loin sur la POO, nous vous conseillons de lire des ressources
est souvent utilisée lorsqu’une classe hérite d’une autre classe pour faire appel au constructeur de la classe mère. La raison est supplémentaires. En langue française, vous trouverez les livres de Gérard Swinnen 9 , Bob Cordeau et Laurent Pointal 10 , et
que nous souhaitons appeler une méthode de la classe mère qui a le même nom qu’une méthode de la classe fille. Dans ce cas, Vincent Legoff 11 .
si on utilisait self.__init__(), cela correspondrait à la fonction de notre classe fille Citron. En mettant systématiquement
une syntaxe
ClasseMere.__init__() on indique sans ambiguïté qu’on appelle le constructeur de la classe mère, en mettant expli-
citement son nom. Ce mécanisme est assez souvent utilisé dans le module Tkinter (voir chapitre 20) pour la construction
d’interfaces graphiques, nous en verrons de nombreux exemples. 19.5 Accès et modifications des attributs depuis l’extérieur
Remarque 19.5.1 Le problème
Si vous utilisez des ressources externes, il se peut que vous rencontriez une syntaxe super().__init__(). La fonction On a vu jusqu’à maintenant que Python était très permissif concernant le changement de valeur de n’importe quel attribut
Python interne super() appelle automatiquement la classe mère sans que vous ayez à donner son nom. Même si cela peut depuis l’extérieur. On a vu aussi qu’il était même possible de créer de nouveaux attributs depuis l’extérieur ! Dans d’autres
paraître pratique, nous vous conseillons d’utiliser dans un premier temps la syntaxe langages orientés objet ceci n’est pas considéré comme une bonne pratique. Il est plutôt recommandé de définir une interface,
ClasseMere.__init__() qui est selon nous plus lisible (on voit explicitement le nom de la classe employée, même s’il y a c’est-à-dire tout un jeu de méthodes accédant ou modifiant les attributs. Ainsi, le concepteur de la classe a la garantie que
plusieurs classes mères). celle-ci est utilisée correctement du « côté client ».
Ce mécanisme n’est pas obligatoirement utilisé, mais il est très utile lorsqu’une classe fille a besoin d’initialiser des Remarque
attributs définis dans la classe mère. On le croise donc souvent car : Cette stratégie d’utiliser uniquement l’interface de la classe pour accéder aux attributs provient des langages orientés objet
— Cela donne la garantie que toutes les variables de la classe mère sont bien initialisées. On réduit ainsi les risques de comme Java et C++. Les méthodes accédant ou modifiant les attributs s’appellent aussi des getters et setters (en français on dit
dysfonctionnement des méthodes héritées de la classe mère. accesseurs et mutateurs). Un des avantages est qu’il est ainsi possible de vérifier l’intégrité des données grâce à ces méthodes :
— Finalement, autant ré-utiliser les « moulinettes » de la classe mère, c’est justement à ça que sert l’héritage ! Au final, si par exemple on souhaitait avoir un entier seulement, ou bien une valeur bornée, on peut facilement ajouter des tests dans
on écrit moins de lignes de code. le setter et renvoyer une erreur à l’utilisateur de la classe s’il n’a pas envoyé le bon type (ou la bonne valeur dans l’intervalle
imposé).
Conseil
Pour les deux raisons citées ci-dessus, nous vous conseillons de systématiquement utiliser le constructeur de la classe mère Regardons à quoi pourrait ressembler une telle stratégie en Python :
lors de l’instanciation. 1 class Citron :
2 def __init__ ( self , couleur =" jaune " , masse =0):
3 self . couleur = couleur
4 self . masse = masse # masse en g
Vous avez à présent bien compris le fonctionnement du mécanisme de l’héritage. Dans notre exemple, nous pourrions 5
créer de nouveaux fruits avec un minimum d’effort. Ceux-ci pourraient hériter de la classe mère Fruit à nouveau, et nous 6 def get_couleur ( self ):
7 return self . couleur
n’aurions pas à réécrire les mêmes méthodes pour chaque fruit, simplement à les appeler. Par exemple : 8
9 def set_couleur ( self , value ):
1 class Kaki ( Fruit ): 10 self . couleur = value
2 def __init__ ( self , taille = None , masse = None , saveur = None , forme = None ): 11
3 Fruit . __init__ ( self , taille , masse , saveur , forme ) 12 def get_masse ( self ):
4 13 return self . masse
5 def __str__ ( self ): 14
6 return Fruit . af fiche_c onseil ( self , " Kaki " , 15 def set_masse ( self , value ):
7 " Bon à manger cru , miam !") 16 if value < 0:
8 17 raise ValueError (" Z ' avez d é j à vu une masse n é gative ???")
9 18 self . masse = value
10 class Orange ( Fruit ): 19
11 def __init__ ( self , taille = None , masse = None , saveur = None , forme = None ): 20
12 Fruit . __init__ ( self , taille , masse , saveur , forme ) 21 if __name__ == " __main__ ":
13
14 def __str__ ( self ): 9. https://inforef.be/swi/python.htm
15 return Fruit . af fiche_c onseil ( self , " Orange " , " Trop bon en jus !") 10. https://perso.limsi.fr/pointal/python:courspython3
11. https://openclassrooms.com/fr/courses/235344-apprenez-a-programmer-en-python
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 211 212 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.5. Accès et modifications des attributs depuis l’extérieur Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.5. Accès et modifications des attributs depuis l’extérieur
22 # d é finition de citron1 La méthode pythonique est plus « douce » à lire, on parle aussi de syntactic sugar ou littéralement en français « sucre
23 citron1 = Citron () syntaxique ». De plus, à l’intérieur de la classe, il faut définir un getter et un setter pour chaque attribut, ce qui multiple les
24 print ( citron1 . get_couleur () , citron1 . get_masse ())
25 # on change les attributs de citron1 avec les setters lignes de code.
26 citron1 . set_couleur (" jaune fonc é ") Très bien. Donc en Python, on n’utilise pas comme dans les autres langages orientés objet les getters et les setters ? Mais,
27 citron1 . set_masse (100)
28 print ( citron1 . get_couleur () , citron1 . get_masse ()) tout de même, cela avait l’air une bonne idée de pouvoir contrôler comment un utilisateur de la classe interagit avec certains
attributs (par exemple, rentre-t-il une bonne valeur ?). N’existe-t-il pas un moyen de faire ça en Python ? La réponse est : bien
Lignes 6 à 10. On définit deux méthodes getters pour accéder à chaque attribut. sûr il existe un moyen pythonique, la classe property. Nous allons voir cette nouvelle classe dans la prochaine rubrique et
Lignes 12 à 18. On définit deux méthodes setters pour modifier chaque attribut. Notez qu’en ligne 16 nous testons si la nous vous dirons comment opérer systématiquement pour accéder, modifier, voire détruire, chaque attribut d’instance de votre
masse est négative, si tel est le cas nous générons une erreur avec le mot-clé raise (cf. chapitre 21 Remarques complémen- classe.
taires). Ceci représente un des avantages des setters : contrôler la validité des attributs (on pourrait aussi vérifier qu’il s’agit
d’un entier, etc.). 19.5.2 La solution : la classe property
Lignes 22 à 28. Après instanciation, on affiche la valeur des attributs avec les deux fonctions getters, puis on les modifie
avec les setters et on les réaffiche à nouveau. Dans la rubrique précédente, on vient de voir que les getters et setters traditionnels rencontrés dans d’autres langages orien-
L’exécution de ce code donnera la sortie suivante : tés objet ne représentent pas une pratique pythonique. En Python, pour des raisons de lisibilité, il faudra dans la mesure du pos-
1 jaune 0
sible conserver une syntaxe instance.attribut pour l’accès aux attributs d’instance, et une syntaxe instance.attribut
2 jaune fonc é 100 = nouvelle_valeur pour les modifier.
Toutefois, si on souhaite contrôler l’accès, la modification (voire la destruction) de certains attributs stratégiques, Python
Si on avait mis citron1.set_masse(-100) en ligne 26, la sortie aurait été la suivante : met en place une classe nommée property. Celle-ci permet de combiner le maintien de la syntaxe lisible instance.attribut,
1 jaune 0 tout en utilisant en filigrane des fonctions pour accéder, modifier, voire détruire l’attribut (à l’image des getters et setters évo-
2 Traceback ( most recent call last ): qués ci-dessus, ainsi que des deleters ou encore destructeurs en français). Pour faire cela, on utilise la fonction Python interne
3 File "./ getter_setter . py " , line 26 , in < module >
4 citron1 . set_masse ( -100) property() qui crée un objet (ou instance) property :
5 File "./ getter_setter . py " , line 17 , in set_masse 1 attribut = property ( fget = accesseur , fset = mutateur , fdel = destructeur )
6 raise ValueError (" Z ' avez d é j à vu une masse n é gative ???")
ValueError : Z ' avez d é j à vu une masse n é gative ???
Les arguments passés à property() sont systématiquement des méthodes dites callback, c’est-à-dire des noms de mé-
7
La fonction interne raise nous a permis de générer une erreur car l’utilisateur de la classe (c’est-à-dire nous dans le thodes que l’on a définies précédemment dans notre classe, mais on ne précise ni argument, ni parenthèse, ni self (voir le
programme principal) n’a pas rentré une valeur correcte. chapitre 20 Fenêtres graphiques et Tkinter). Avec cette ligne de code, attribut est un objet de type property qui fonctionne
On comprend bien l’utilité d’une stratégie avec des getters et setters dans cet exemple. Toutefois, en Python, on peut très de la manière suivante à l’extérieur de la classe :
bien accéder et modifier les attributs même si on a des getters et des setters dans la classe. Imaginons la même classe Citron — L’instruction instance.attribut appellera la méthode .accesseur().
que ci-dessus, mais on utilise le programme principal suivant (notez que nous avons simplement ajouter les lignes 9 à 12 — L’instruction instance.attribut = valeur appellera la méthode
ci-dessous) : .mutateur().
— L’instruction del instance.attribut appellera la méthode
if __name__ == " __main__ ":
.destructeur().
1
2 # d é finition de citron1
3 citron1 = Citron () L’objet attribut est de type property, et la vraie valeur de l’attribut est stockée par Python dans une variable d’instance
print ( citron1 . get_couleur () , citron1 . get_masse ())
4
5 # on change les attributs de citron1 avec les setters qui s’appellera par exemple _attribut (même nom mais commençant par un underscore unique, envoyant un message à
6 citron1 . set_couleur (" jaune fonc é ") l’utilisateur qu’il s’agit d’une variable associée au comportement interne de la classe).
7 citron1 . set_masse (100) Comment cela fonctionne-t-il concrètement dans un code ? Regardons cet exemple (nous avons mis des print() un peu
8 print ( citron1 . get_couleur () , citron1 . get_masse ())
9 # on les rechange sans les setters partout pour bien comprendre ce qui se passe) :
10 citron1 . couleur = " pourpre profond "
11 citron1 . masse = -15 1 class Citron :
12 print ( citron1 . get_couleur () , citron1 . get_masse ()) 2 def __init__ ( self , masse =0):
3 print ("(2) J ' arrive dans le . __init__ ()")
4 self . masse = masse
Cela donnera la sortie suivante : 5
6 def get_masse ( self ):
jaune 0
print (" Coucou je suis dans le get ")
1
jaune fonc é 100 7
return self . _masse
2
3 pourpre profond -15 8
9
10 def set_masse ( self , valeur ):
Malgré la présence des getters et des setters, nous avons réussi à accéder et à modifier la valeur des attributs. De plus, nous 11 print (" Coucou je suis dans le set ")
avons pu mettre une valeur aberrante (masse négative) sans que cela ne génère une erreur ! 12 if valeur < 0:
13 raise ValueError (" Un citron ne peut pas avoir "
Vous vous posez sans doute la question : mais dans ce cas, quel est l’intérêt de mettre des getters et des setters en Python ? 14 " de masse n é gative !")
La réponse est très simple : cette stratégie n’est pas une manière « pythonique » d’opérer (voir le chapitre 15 Bonnes pratiques 15 self . _masse = valeur
16
en programmation Python pour la définition de « pythonique »). En Python, la lisibilité est la priorité. Souvenez-vous du Zen 17 masse = property ( fget = get_masse , fset = set_masse )
de Python « Readability counts » (voir le chapitre 15). 18
19
De manière générale, une syntaxe avec des getters et setters du côté client surcharge la lecture. Imaginons que l’on ait une 20 if __name__ == " __main__ ":
instance nommée obj et que l’on souhaite faire la somme de ses trois attributs x, y et z : 21 print ("(1) Je suis dans le programme principal , "
22 " je vais instancier un Citron ")
1 # pythonique 23 citron = Citron ( masse =100)
2 obj . x + obj . y + obj . z 24 print ("(3) Je reviens dans le programme principal ")
3 25 print ( f " La masse de notre citron est { citron . masse } g ")
4 # non pythonique 26 # on mange le citron
5 obj . get_x () + obj . get_y () + obj . get_z () 27 citron . masse = 25
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 213 214 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.5. Accès et modifications des attributs depuis l’extérieur Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.6. Bonnes pratiques pour construire et manipuler ses classes
28 print ( f " La masse de notre citron est { citron . masse } g ") 19.6 Bonnes pratiques pour construire et manipuler ses classes
29 print ( citron . __dict__ )
Pour une fois, nous allons commenter les lignes dans le désordre : Nous allons voir dans cette rubrique certaines pratiques que nous vous recommandons lorsque vous construisez vos propres
Ligne 17. Il s’agit de la commande clé pour mettre en place le système : masse devient ici un objet de type property (si classes.
on regarde son contenu avec une syntaxe NomClasse.attribut_property, donc ici Citron.masse, Python nous renverra
quelque chose de ce style : <property object at 0x7fd3615aeef8>). Qu’est-ce que cela signifie ? Et bien la prochaine 19.6.1 L’accès aux attributs
fois qu’on voudra accéder au contenu de cet attribut .masse, Python appellera la méthode .get_masse(), et quand on voudra
On a vu dans la rubrique Accès et modifications des attributs depuis l’extérieur que nous avions le moyen de contrôler
le modifier, Python appellera la méthode .set_masse() (ceci sera valable de l’intérieur ou de l’extérieur de la classe). Comme
cet accès avec la classe property. Toutefois, cela peut parfois alourdir inutilement le code, ce qui va à l’encontre de certains
il n’y a pas de méthode destructeur (passée avec l’argument fdel), on ne pourra pas détruire cet attribut : un del c.masse
préceptes de la PEP 20 comme « Sparse is better than dense », « Readability counts », etc. (voir le chapitre 15 Bonnes
conduirait à une erreur de ce type : AttributeError: can't delete attribute.
pratiques en programmation Python).
Ligne 4. Si vous avez bien suivi, cette commande self.masse = masse dans le constructeur va appeler automatiquement
la méthode .set_masse(). Attention, dans cette commande, la variable masse à droite du signe = est une variable locale
passée en argument. Par contre, self.masse sera l’objet de type property. Si vous avez bien lu la rubrique Différence entre Conseil
les attributs de classe et d’instance, l’objet masse créé en ligne 16 est un attribut de classe, on peut donc y accéder avec une Si on souhaite contrôler ce que fait le client de la classe pour certains attributs « délicats » ou « stratégiques », on peut
syntaxe self.masse au sein d’une méthode. utiliser la classe property. Toutefois, nous vous conseillons de ne l’utiliser que lorsque cela se révèle vraiment nécessaire,
donc avec parcimonie. Le but étant de ne pas surcharger le code inutilement. Cela va dans le sens des recommandations des
développeurs de Python (comme décrit dans la PEP8).
Conseil
Notez bien l’utilisation de self.masse dans le constructeur (en ligne 4) plutôt que self._masse. Comme self.masse
appelle la méthode .set_masse(), cela permet de contrôler si la valeur est correcte dès l’instanciation. C’est donc une Les objets property ont deux avantages principaux :
pratique que nous vous recommandons. Si on avait utilisé self._masse, il n’y aurait pas eu d’appel à la fonction mutateur et — ils permettent de garder une lisibilité du côté client avec une syntaxe
on aurait pu mettre n’importe quoi, y compris une valeur aberrante, lors de l’instanciation. instance.attribut ;
— même si un jour vous décidez de modifier votre classe et de mettre en place un contrôle d’accès à certains attributs
avec des objets property, cela ne changera rien du côté client. Ce dernier utilisera toujours instance.attribut ou
Lignes 6 à 15. Dans les méthodes accesseur et mutateur, on utilise la variable
instance.attribut = valeur. Tout cela contribuera à une meilleure maintenance du code client utilisant votre
self._masse qui contiendra la vraie valeur de la masse du citron (cela serait vrai pour tout autre objet de type property).
classe.
Certains détracteurs disent qu’il est parfois difficile de déterminer qu’un attribut est contrôlé avec un objet property. La
Attention réponse à cela est simple, dites-le clairement dans la documentation de votre classe via les docstrings (voir la rubrique ci-
Dans les méthodes accesseur et mutateur il ne faut surtout pas utiliser self.masse à la place de self._masse. Pourquoi ? dessous).
Par exemple, dans l’accesseur, si on met self.masse cela signifie que l’on souhaite accéder à la valeur de l’attribut (comme
dans le constructeur !). Ainsi, Python rappellera l’accesseur et retombera sur self.masse, ce qui rappellera l’accesseur et
ainsi de suite : vous l’aurez compris, cela partira dans une récursion infinie et mènera à une erreur du type RecursionError: 19.6.2 Note sur les attributs publics et non publics
maximum recursion depth exceeded. Cela serait vrai aussi si vous aviez une fonction destructeur, il faudrait utiliser Certains langages orientés objet mettent en place des attributs dits privés dont l’accès est impossible de l’extérieur de
self._masse). la classe. Ceux-ci existent afin d’éviter qu’un client n’aille perturber ou casser quelque chose dans la classe. Les arguments
auxquels l’utilisateur a accès sont dits publics.
L’exécution de ce code donnera :
Attention
1 (1) Dans le programme principal , je vais instancier un Citron
2 (2) J ' arrive dans le . __init__ () En Python, il n’existe pas d’attributs privés comme dans d’autres langages orientés objet. L’utilisateur a accès à tous les
3 Coucou je suis dans le set attributs quels qu’ils soient, même s’ils contiennent un ou plusieurs caractère(s) underscore(s) (cf. ci-desssous) !
4 (3) Je reviens dans le programme principal
5 Coucou je suis dans le get
6 La masse de notre citron est 100 g
7 Coucou je suis dans le set Au lieu de ça, on parle en Python d’attributs publics et non publics.
8 Coucou je suis dans le get
9 La masse de notre citron est 25 g
10 { ' _masse ': 25}
Définition
Cette exécution montre qu’à chaque appel de self.masse ou citron.masse on va utiliser les méthodes accesseur ou En Python les attributs non publics sont des attributs dont le nom commence par un ou deux caractère(s) underscore. Par
mutateur. La dernière commande qui affiche le contenu de citron.__dict__ montre que la vraie valeur de l’attribut est exemple, _attribut, ou __attribut.
stockée dans la variable d’instance ._masse (instance._masse de l’extérieur et self._masse de l’intérieur).
La présence des underscores dans les noms d’attributs est un signe clair que le client ne doit pas y toucher. Toutefois, cela
Pour aller plus loin n’est qu’une convention, et comme dit ci-dessus le client peut tout de même modifier ces attributs.
Il existe une autre syntaxe considérée comme plus élégante pour mettre en place les objets property. Il s’agit des déco- Par exemple, reprenons la classe Citron de la rubrique précédente dont l’attribut .masse est contrôlé avec un objet
rateurs @property, @attribut.setter et @attribut.deleter. Toutefois, la notion de décorateur va au-delà du présent property :
ouvrage. Si vous souhaitez plus d’informations, vous pouvez consulter par exemple le site programiz 12 ou le livre de Vincent
1 >>> citron = Citron ()
Legoff 13 . 2 Coucou je suis dans le set
3 >>> citron . masse
4 Coucou je suis dans le get
12. https://www.programiz.com/python-programming/property 5 0
13. https://openclassrooms.com/fr/courses/235344-apprenez-a-programmer-en-python 6 >>> citron . masse = -16
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 215 216 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.6. Bonnes pratiques pour construire et manipuler ses classes Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.6. Bonnes pratiques pour construire et manipuler ses classes
Définition Conseil
Le name mangling 14 , ou encore substantypage ou déformation de nom en français, correspond à un mécanisme de chan- En résumé, n’essayez pas de mettre des barrières inutiles vers vos attributs. Cela va à l’encontre de la philosophie Python.
gement du nom d’un attribut selon si on est à l’intérieur ou à l’extérieur d’une classe. Soignez plutôt la documentation et faites confiance aux utilisateurs de votre classe !
Regardons un exemple :
1 class Citron :
2 def __init__ ( self ): 19.6.3 Classes et docstrings
3 self . __mass = 100
4 Les classes peuvent bien sûr contenir des docstrings comme les fonctions et les modules. C’est d’ailleurs une pratique
def get_mass ( self ):
5
6 return self . __mass vivement recommandée. Voici un exemple sur notre désormais familière classe Citron :
7
1 class Citron :
8
""" Voici la classe Citron .
if __name__ == " __main__ ":
2
9
3
10 citron1 = Citron () 4 Il s ' agit d ' une classe assez i mp r essi on nan te qui cr é e des objets
11 print ( citron1 . get_mass ()) 5 citrons .
12 print ( citron1 . __mass ) 6 Par d é faut une instance de Citron contient l ' attribut de classe
7 saveur .
Ce code va donner la sortie suivante : 8 """
9 saveur = " acide "
1 100 10
2 Traceback ( most recent call last ): 11 def __init__ ( self , couleur =" jaune " , taille =" standard "):
3 File "./ pyscripts / mangling . py " , line 11 , in < module > 12 """ Constructeur de la classe Citron .
13
4 print ( citron1 . __mass ) 14 Ce constructeur prend deux arguments par mot - cl é
5 AttributeErro r : ' Citron ' object has no attribute ' __mass ' 15 couleur et taille ."""
16 self . couleur = couleur
La ligne 12 du code a donc conduit à une erreur : Python prétend ne pas connaître l’attribut .__mass. On pourrait croire 17 self . taille = taille
18
que cela constitue un mécanisme de protection des attributs. En fait il n’en est rien, car on va voir que l’attribut est toujours 19 def __str__ ( self ):
accessible et modifiable. Si on modifiait le programme principal comme suit : 20 """ Red é finit le comportement avec print ()."""
return f " saveur : { saveur } , couleur : { couleur } , taille : { taille }"
if __name__ == " __main__ ":
21
1
22
2 citron1 = Citron () 23 def affiche_ coucou ( self ):
3 print ( citron1 . __dict__ ) 24 """ M é thode inutile qui affiche coucou ."""
25 print (" Coucou !")
On obtiendrait en sortie le dictionnaire {'_Citron__mass': 100}.
Le name mangling est donc un mécanisme qui transforme le nom self.__attribut à l’intérieur de la classe en instance._NomClasse__attribut Si on fait help(Citron) dans l’interpréteur, on obtient :
à l’extérieur de la classe. Ce mécanisme a été conçu initialement pour pouvoir retrouver des noms d’attributs identiques lors de 1 Help on class Citron in module __main__ :
l’héritage. Si par exemple une classe mère et une classe fille ont chacune un attribut nommé __attribut, le name mangling 2
3 class Citron ( builtins . object )
permet d’éviter les conflits de nom. Par exemple : 4 | Citron ( couleur = ' jaune ' , taille = ' standard ')
1 class Fruit : 5 |
2 def __init__ ( self ): 6 | Voici la classe Citron .
3 self . __mass = 100 7 |
4 8 | Il s ' agit d ' une classe assez i mp r essi on nan te qui cr é e des objets
5 9 | citrons .
6 class Citron ( Fruit ): 10 | Par d é faut une instance de Citron contient l ' attribut de classe
7 def __init__ ( self ): 11 | saveur .
8 Fruit . __init__ ( self ) 12 |
9 self . __mass = 200 13 | Methods defined here :
14 |
14. https://en.wikipedia.org/wiki/Name_mangling 15 | __init__ ( self , couleur = ' jaune ' , taille = ' standard ')
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 217 218 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.6. Bonnes pratiques pour construire et manipuler ses classes Chapitre 19. Avoir la classe avec les objets Chapitre 19. Avoir la classe avec les objets 19.6. Bonnes pratiques pour construire et manipuler ses classes
Si vous créez des instances sans passer d’argument lors de l’instanciation, toutes ces instances pointeront vers la même 1 >>> citron . _asdict ()
liste. Cela peut avoir des effets désastreux. 2 OrderedDict ([( ' masse ' , 10) , ( ' couleur ' , ' jaune ') , ( ' saveur ' , ' acide ') , ( ' forme ' , ' ellipsoide ')])
— Ne mettez pas non plus une liste vide (ou tout autre objet séquentiel modifiable) comme attribut de classe.
Quand utiliser les namedtuples ? Vous souvenez-vous de la différence entre les listes et les dictionnaires ? Et bien là c’est
1 class Citron :
2 liste = [] un peu la même chose entre les tuples et les namedtuples. Les namedtuples permettent de créer un code plus lisible en
remplaçant des numéros d’indice par des noms. Le fait qu’ils soient non modifiables peut aussi avoir un avantage par rapport
Ici chaque instance pourra modifier la liste, ce qui n’est pas souhaitable. Souvenez vous, la modification des attributs de à l’intégrité des données. Si vous trouvez les namedtuples limités, sachez que vous pouvez créer votre propre classe qui hérite
classe doit se faire par une syntaxe Citron.attribut = valeur (et non pas via les instances). d’un namedtuple afin de lui ajouter de nouvelles méthodes « maison ».
— Comme abordé dans la rubrique Différence entre les attributs de classe et d’instance, nous vous conseillons de ne
jamais modifier les attributs de classe. Vous pouvez néanmois les utiliser comme constantes. Pour aller plus loin
— Si vous avez besoin d’attributs modifiables, utilisez des attributs d’instance et initialisez les dans la méthode .__init__()
(et nulle part ailleurs). Par exemple, si vous avez besoin d’une liste comme attribut, créez la plutôt dans le constructeur : 15. https://docs.python.org/fr/3/library/collections.html#collections.namedtuple
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 219 220 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
19.7. Exercices Chapitre 19. Avoir la classe avec les objets
Pour aller plus loin, vous pouvez consulter le très bon article 16 de Dan Bader.
19.7 Exercices
Conseil : pour ces exercices, créez des scripts puis exécutez-les dans un shell. Chapitre 20
19.7.1 Classe Rectangle
Téléchargez le script rectangle.py 17 qui implémente la classe Rectangle.
Complétez le programme principal pour que le script :
Fenêtres graphiques et Tkinter
— crée une instance rectangle de la classe Rectangle ;
— affiche les attributs d’instance largeur, longueur et couleur ;
— calcule et affiche la surface de rectangle ;
— affiche une ligne vide ;
— change le rectangle en carré de 30 m de côté ; Conseil
— calcule et affiche la surface de ce carré ; Dans ce chapitre, nous allons utiliser des classes, nous vous conseillons de bien relire le chapitre 19 sur le sujet. Par
— crée une autre instance rectangle2 aux dimensions et à la couleur que vous souhaitez (soyez créatif !) et qui affiche ailleurs, nous vous conseillons de relire également la rubrique Arguments positionnels et arguments par mot-clé du chapitre 9
les attributs et la surface de ce nouveau rectangle. sur les fonctions.
19.7.4 Classe Atome améliorée Les arguments passés à la ligne de commande sont tout à fait classiques dans le monde de la bioinformatique. Toutefois,
il se peut que vous développiez un programme pour une communauté plus large, qui n’a pas forcément l’habitude d’utiliser
Améliorez la classe Atome en lui ajoutant un nouvel attribut masse qui correspond à la masse atomique ainsi qu’une un shell et la ligne de commande. Une GUI permettra un usage plus large de votre programme, il est donc intéressant de
nouvelle méthode regarder comment s’y prendre. Dans notre exemple ci-dessus on pourrait par exemple développer une interface où l’utilisateur
.calcule_centre_masse(). Redéfinissez le comportement avec print() (à l’aide de la méthode magique .__str__()) choisirait le nom du fichier d’entrée par l’intermédiaire d’une boîte de dialogue, et de contrôler les options en cliquant sur des
de manière à afficher les coordonnées et la masse de l’atome. boutons, ou des « listes de choix ». Une telle GUI pourrait ressembler à la figure 20.1.
16. https://dbader.org/blog/writing-clean-python-with-namedtuples
17. https://python.sdv.univ-paris-diderot.fr/data-files/rectangle.py
18. https://python.sdv.univ-paris-diderot.fr/livre-dunod F IGURE 20.1 – Exemple de GUI.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 221 222
20.2. Quelques concepts liés à la programmation graphique Chapitre 20. Fenêtres graphiques et Tkinter Chapitre 20. Fenêtres graphiques et Tkinter 20.3. Notion de fonction callback
Au delà de l’aspect convivial pour l’utilisateur, vous pourrez, avec une GUI, construire des fenêtres illustrant des éléments
que votre programme génère à la volée. Ainsi, vous « verrez » ce qui se passe de manière explicite et en direct ! Par exemple,
si on réalise une simulation de particules, on a envie de voir un « film » des particules en mouvement, c’est-à-dire comment
ces particules bougent au fur et à mesure que les pas de simulation avancent. Une GUI vous permettra une telle prouesse !
Enfin, sachez que certains logiciels scientifiques ont été développés avec la bibliothèque graphique Tk (par exemple pymol,
vmd, etc.). Qui sait, peut-être serez-vous le prochain développeur d’un outil incontournable ?
Il existe beaucoup de modules pour construire des applications graphiques. Par exemple : Tkinter 1 , wxpython 2 , PyQt 3 ,
PyGObject 4 , etc. Nous présentons dans ce chapitre le module Tkinter qui est présent de base dans les distributions Python (pas
besoin a priori de faire d’installation de module externe). Tkinter permet de piloter la bibliothèque graphique Tk (Tool Kit),
Tkinter signifiant tk interface. On pourra noter que cette bibliothèque Tk peut être également pilotée par d’autres langages
(Tcl, perl, etc.).
20.2 Quelques concepts liés à la programmation graphique F IGURE 20.2 – Exemple de fonction callback dans Python Tutor.
Lorsque l’on développe une GUI, nous créons une fenêtre graphique contenant notre application, ainsi que des widgets
inclus dans la fenêtre. 1 var = fct ( arg1 , arg2 )
2
3 obj . methode ( arg )
Définition
Les widgets (window gadget) sont des objets graphiques permettant à l’utilisateur d’interagir avec votre programme Python où les arguments étaient des objets « classiques » (par exemple une chaîne de caractères, un entier, un float, etc.).
de manière conviviale. Par exemple, dans la fenêtre sur la figure 20.1, les boutons, les listes de choix, ou encore la zone de Sachez qu’il est possible de passer en argument une fonction à une autre fonction ! Par exemple :
texte sont des widgets. 1 def fct_callback ( arg ):
2 print ( f "J ' aime bien les { arg } !")
3
4
L’utilisation d’une GUI va amener une nouvelle manière d’aborder le déroulement d’un programme, il s’agit de la pro- 5 def une_fct ( ma_callback ):
grammation dite « événementielle ». Jusqu’à maintenant vous avez programmé « linéairement », c’est-à-dire que les instruc- 6 print (" Je suis au d é but de une_fct () , "
7 " et je vais ex é cuter la fonction callback :")
tions du programme principal s’enchaînaient les unes derrière les autres (avec bien sûr de possibles appels à des fonctions). 8 ma_callback (" fraises ")
Avec une GUI, l’exécution est décidée par l’utilisateur en fonction de ses interactions avec les différents widgets. Comme c’est 9 print (" une_fct () se termine .")
10
l’utilisateur qui décide quand et où il clique dans l’interface, il va falloir mettre en place ce qu’on appelle un « gestionnaire 11 if __name__ == " __main__ ":
d’événements ». 12 une_fct ( fct_callback )
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 223 224 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
20.4. Prise en main du module Tkinter Chapitre 20. Fenêtres graphiques et Tkinter Chapitre 20. Fenêtres graphiques et Tkinter 20.5. Construire une application Tkinter avec une classe
3 >>> label = tk . Label ( racine , text =" J ' adore Python !") 3 racine = tk . Tk ()
4 >>> bouton = tk . Button ( racine , text =" Quitter " , fg =" red " , 4 label = tk . Label ( racine , text =" J ' adore Python !")
5 ... command = racine . destroy ) 5 bouton = tk . Button ( racine , text =" Quitter " , command = racine . quit )
6 >>> label . pack () 6 bouton [" fg "] = " red "
7 >>> bouton . pack () 7 label . pack ()
8 >>> 8 bouton . pack ()
9 racine . mainloop ()
Ligne 2. On crée la fenêtre principale (vous la verrez apparaître !). Pour cela, on crée une instance de la classe tk.Tk dans 10 print (" C ' est fini !")
la variable racine. Tous les widgets que l’on créera ensuite seront des fils de cette fenêtre. On pourra d’ailleurs noter que cette puis lançons ce script depuis un shell :
classe tk.Tk ne s’instancie en général qu’une seule fois par programme. Vous pouvez, par curiosité, lancer une commande
$ python tk_exemple . py
dir(racine) ou help(racine), vous verrez ainsi les très nombreuses méthodes et attributs associés à un tel objet Tk.
1
Ligne 3. On crée un label, c’est-à-dire une zone dans la fenêtre principale où on écrit un texte. Pour cela, on a créé Vous voyez maintenant la même fenêtre avec les mêmes fonctionnalités par rapport à la version dans l’interpréteur (voir
une variable label qui est une instance de la classe tk.Label. Cette variable label contient donc notre widget, nous la la figure 20.3). Nous commentons ici les différences (dans le désordre) :
réutiliserons plus tard (par exemple pour placer ce widget dans la fenêtre). Notez le premier argument positionnelracine Ligne 6. Le bouton a été créé en ligne 5, mais on voit qu’il est possible de préciser une option de rendu du widget après
passé à la classe tk.Label, celui-ci indique la fenêtre parente où doit être dessinée le label. Cet argument doit toujours être cette création (ici on met le texte en rouge avec l’option "fg"). La notation ressemble à celle d’un dictionnaire avec une
passé en premier et il est vivement conseillé de le préciser. Nous avons passé un autre argument avec le nom text pour syntaxe générale widget["option"] = valeur.
indiquer, comme vous l’avez deviné, le texte que nous souhaitons voir dans ce label. La classe tk.Label peut recevoir de Ligne 9. L’instruction racine.mainloop() va lancer le gestionnaire d’événements que nous avons évoqué ci-dessus.
nombreux autres arguments, en voici la liste exhaustive 6 . Dans les fonctions Tkinter qui construisent un widget, les arguments C’est lui qui interceptera la moindre action de l’utilisateur, et qui lancera les portions de code associées à chacune de ses
possibles pour la mise en forme de celui-ci sont nombreux, si bien qu’ils sont toujours des arguments par mot-clé. Si on ne actions. Bien sûr, comme nous développerons dans ce qui va suivre toutes nos applications Tkinter dans des scripts (et non
précise pas un de ces arguments lors de la création du widget, l’argument prendra alors une valeur par défaut. Cette liste pas dans l’interpréteur), cette ligne sera systématiquement présente. Elle sera souvent à la fin du script, puisque, à l’image
des arguments par mot-clé est tellement longue qu’en général on ne les précisera pas tous. Heureusement, Python autorise de ce script, on écrit d’abord le code construisant l’interface, et on lance le gestionnaire d’événements une fois l’interface
l’utilisation des arguments par mot-clé dans un ordre quelconque. Comme nous l’avons vu dans le chapitre 9 Fonctions, complètement décrite, ce qui lancera au final l’application.
souvenez vous que leur utilisation dans le désordre implique qu’il faudra toujours préciser leur nom : par exemple vous écrirez Ligne 10. Cette ligne ne s’exécute qu’après l’arrêt de l’application (soit en cliquant sur le bouton « Quitter », soit en
text="blabla" et non pas "blabla" tout court. cliquant sur la croix).
Ligne 4. De même, on crée un bouton « Quitter » qui provoquera la fermeture de la fenêtre et donc l’arrêt de l’application Ligne 5. Pour quitter l’application, on utilise ici la méthode .quit(). Celle-ci casse la .mainloop() et arrête ainsi le
si on clique dessus. À nouveau, on passe la fenêtre parente en premier argument, le texte à écrire dans le bouton, puis la gestionnaire d’événements. Cela mène à l’arrêt de l’application. Dans le premier exemple dans l’interpréteur, on avait utilisé
couleur de ce texte. Le dernier argument command=racine.destroy va indiquer la fonction / méthode à exécuter lorsque la méthode .destroy() sur la fenêtre principale. Comme son nom l’indique, celle-ci détruit la fenêtre principale et mène
l’utilisateur clique sur le bouton. On pourra noter que l’instance de la fenêtre mère tk.Tk (que nous avons nommée racine) aussi à l’arrêt de l’application. Cette méthode aurait donc également fonctionné ici. Par contre, la méthode .quit() n’aurait
possède une méthode .destroy() qui va détruire le widget sur lequel elle s’applique. Comme on tue la fenêtre principale (que pas fonctionné dans l’interpréteur car, comme on l’a vu, la boucle .mainloop() n’y est pas présente. Comme nous écrirons
l’on peut considérer comme un widget contenant d’autres widgets), tous les widgets fils seront détruits et donc l’application systématiquement nos applications Tkinter dans des scripts, et que la boucle .mainloop() y est obligatoire, vous pourrez
s’arrêtera. Vous voyez par ailleurs que cette méthode racine.destroy est passée à l’argument command= sans parenthèses utiliser au choix .quit() ou .destroy() pour quitter l’application.
ni arguments : il s’agit donc d’une fonction callback comme expliqué ci-dessus. Dans tous les widgets Tkinter, on doit
passer à l’argument command=... une fonction / méthode callback. La liste exhaustive des arguments possibles de la classe
tk.Button se trouve ici 7 . 20.5 Construire une application Tkinter avec une classe
Lignes 6 et 7. Vous avez noté que lors de la création de ce label et de ce bouton, rien ne s’est passé dans la fenêtre. C’est
normal, ces deux widgets existent bien, mais il faut maintenant les placer à l’intérieur de la fenêtre. On appelle pour ça la De manière générale, il est vivement conseillé de développer ses applications Tkinter en utilisant une classe. Cela présente
méthode .pack(), avec une notation objet widget.pack() : à ce moment précis, vous verrez votre label apparaître ainsi que l’avantage d’encapsuler l’application de manière efficace et d’éviter ainsi l’utilisation de variables globales. Souvenez-vous,
la fenêtre qui se redimensionne automatiquement en s’adaptant à la grandeur de votre label. L’invocation de la même méthode elles sont à bannir définitivement ! Une classe crée un espace de noms propre à votre application, et toutes les variables
pour le bouton va faire apparaître celui-ci juste en dessous du label et redimensionner la fenêtre. Vous l’aurez compris la nécessaires seront ainsi des attributs de cette classe. Reprenons notre petit exemple avec un label et un bouton :
méthode .pack() place les widgets les uns en dessous des autres et ajuste la taille de la fenêtre. On verra plus bas que l’on 1 import tkinter as tk
peut passer des arguments à cette méthode pour placer les widgets différemment (en haut, à droite, à gauche). 2
3 class Application ( tk . Tk ):
Au final, vous devez obtenir une fenêtre comme sur la figure 20.3. 4 def __init__ ( self ):
5 tk . Tk . __init__ ( self )
6. http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/label.html 6 self . creer_widgets ()
7. http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/button.html 7
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 225 226 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
20.6. Le widget canvas Chapitre 20. Fenêtres graphiques et Tkinter Chapitre 20. Fenêtres graphiques et Tkinter 20.6. Le widget canvas
Ligne 3. On crée notre application en tant que classe. Notez que cette classe porte un nom qui commence par une majuscule
(comme recommandé dans les bonnes pratiques de la PEP8 8 , cf. chapitre 15). L’argument passé dans les parenthèses indique
que notre classe Application hérite de la classe tk.Tk. Par ce mécanisme, nous héritons ainsi de toutes les méthodes et
attributs de cette classe mère, mais nous pouvons en outre en ajouter de nouvelles/nouveaux (on parle aussi de « redéfinition
» de la classe tk.Tk) !
Ligne 4. On crée un constructeur, c’est-à-dire une méthode qui sera exécutée lors de l’instanciation de notre classe (à la
ligne 16).
Ligne 5. On appelle ici le constructeur de la classe mère tk.Tk.__init__(). Pourquoi fait-on cela ? On se souvient dans
la version linéaire de l’application, on avait utilisé une instanciation classique : racine = tk.Tk(). Ici, l’effet de l’appel
du constructeur de la classe mère permet d’instancier la fenêtre Tk dans la variable self directement. C’est-à-dire que la
prochaine fois que l’on aura besoin de cette instance (lors de la création des widgets par exemple, cf. lignes 9 et 10), on
F IGURE 20.4 – Exemple 1 de canvas avec le système de coordonnées. Le système de coordonnées est montré en vert et
utilisera directement self plutôt que racine ou tout autre nom donné à l’instance. Comme vu dans le chapitre 19 Avoir la
n’apparaît pas sur la vraie fenêtre Tkinter.
classe avec les objets, appeler le constructeur de la classe mère est une pratique classique lorsqu’une classe hérite d’une autre
classe.
Ligne 6. On appelle la méthode self.creer_widgets() de notre classe Application. Pour rappel, le self avant le La classe tk.Canvas crée un widget canvas (ou encore canevas en français). Cela va créer une zone (i.e. le canevas en
.creer_widgets() indique qu’il s’agit d’une méthode de notre classe (et non pas d’une fonction classique). tant que tel) dans laquelle nous allons dessiner divers objets tels que des ellipses, lignes, polygones, etc., ou encore insérer
Ligne 8. La méthode .creer_widgets() va créer des widgets dans l’application. du texte ou des images. Regardons tout d’abord un code minimal qui construit un widget canvas, dans lequel on y dessine un
Ligne 9. On crée un label en instanciant la classe tk.Label(). Notez que le premier argument passé est maintenant self cercle et deux lignes :
(au lieu de racine précédemment) indiquant la fenêtre dans laquelle sera construit ce widget.
import tkinter as tk
Ligne 10. De même on crée un widget bouton en instanciant la classe tk.Button(). Là aussi, l’appel à la méthode 1
2
.quit() se fait par self.quit puisque la fenêtre est instanciée dans la variable self. Par ailleurs, on ne met ni parenthèses 3 racine = tk . Tk ()
ni arguments à self.quit car il s’agit d’une fonction callback (comme dans la rubrique précédente). 4 canv = tk . Canvas ( racine , bg =" white " , height =200 , width =200)
5 canv . pack ()
Lignes 11 et 12. On place les deux widgets dans la fenêtre avec la méthode .pack(). 6 canv . create_oval (0 , 0 , 200 , 200 , outline =" red " , width =10)
Ligne 15. Ici on autorise le lancement de notre application Tkinter en ligne de commande (python tk_application.py), 7 canv . create_line (0 , 0 , 200 , 200 , fill =" black " , width =10)
8 canv . create_line (0 , 200 , 200 , 0 , fill =" black " , width =10)
ou bien de réutiliser notre classe en important tk_application.py en tant que module (import tk_application) (voir 9 racine . mainloop ()
le chapitre 14 Création de modules).
Ligne 16. On instancie notre application. Ligne 4. On voit qu’il faut d’abord créer le widget canvas, comme d’habitude en lui passant l’instance de la fenêtre
Ligne 17. On donne un titre dans la fenêtre de notre application. Comme on utilise de petits widgets avec la méthode principale en tant qu’argument positionnel, puis les options. Notons que nous lui passons comme options la hauteur et la
pack(), il se peut que le titre ne soit pas visible lors du lancement de l’application. Toutefois, si on « étire » la fenêtre à la largeur du canvas. Même s’il s’agit d’arguments par mot-clé, donc optionnels, c’est une bonne pratique de les préciser. En
souris, le titre le deviendra. On pourra noter que cette méthode .title() est héritée de la classe mère Tk. effet, les valeurs par défaut risqueraient de nous mener à dessiner hors de la zone visible (cela ne génère pas d’erreur mais n’a
Ligne 18. On lance le gestionnaire d’événements. guère d’intérêt).
Au final, vous obtiendrez le même rendu que précédemment (cf. figure 20.3). Alors vous pourrez-vous poser la question, Ligne 6 à 8. Nous dessinons maintenant des objets graphiques à l’intérieur du canevas avec les méthodes .create_oval()
« pourquoi ai-je besoin de toute cette structure alors que le code précédent semblait plus direct ? ». La réponse est simple, (dessine une ellipse) et .create_line() (dessine une ligne). Les arguments positionnels sont les coordonnées de l’ellipse
lorsqu’un projet de GUI grossit, le code devient très vite illisible s’il n’est pas organisé en classe. De plus, la non-utilisation de (les deux points englobant l’ellipse, cf. ce lien 10 pour la définition exacte) ou de la ligne. Ensuite, on passe comme d’habitude
classe rend quasi-obligatoire l’utilisation de variables globales, ce qui on l’a vu, est à proscrire définitivement ! Dans la suite des arguments par mot-clé (vous commencez à avoir l’habitude !) pour mettre en forme ces objets graphiques.
du chapitre, nous verrons quelques exemples qui illustrent cela (cf. la rubrique suivante). Le rendu de l’image est montré dans la figure 20.4 ainsi que le système de coordonnées associé au canvas. Comme dans
la plupart des bibliothèques graphiques, l’origine du repère du canvas (i.e. la coordonnée (0, 0)) est en haut à gauche. Les x
vont de gauche à droite, et les y vont de haut en bas.
20.6 Le widget canvas
Attention
20.6.1 Un canvas simple et le système de coordonnées L’axe des y est inversé par rapport à ce que l’on représente en mathématique. Si on souhaite représenter une fonction
Le widget canvas 9 de Tkinter est très puissant. Il permet de dessiner des formes diverses (lignes, cercles, etc.), et même mathématique (ou tout autre objet dans un repère régi par un repère mathématique), il faudra faire un changement de repère.
de les animer !
8. https://www.python.org/dev/peps/pep-0008/
9. http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/canvas.html 10. http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/create_oval.html
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 227 228 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
20.6. Le widget canvas Chapitre 20. Fenêtres graphiques et Tkinter Chapitre 20. Fenêtres graphiques et Tkinter 20.6. Le widget canvas
Lignes 4 à 6. Comme montré dans la rubrique Construire une application Tkinter avec une classe, notre classe AppliCanevas
hérite de la classe générale tk.Tk et la fenêtre Tk se retrouve dans la variable self.
Ligne 7. On crée un attribut de la classe self.size qui contiendra la taille (hauteur et largeur) du canvas. On rappelle
que cet attribut sera visible dans l’ensemble de la classe puisqu’il est « accroché » à celle-ci par le self.
Ligne 8. On lance la méthode .creer_widgets() (qui est elle aussi « accrochée » à la classe par le self).
Lignes 12 à 14. On crée un widget canvas en instanciant la classe tk.Canvas. On place ensuite le canvas dans la fenêtre
avec la méthode .pack() en lui précisant où le placer avec la variable Tkinter tk.LEFT.
Lignes 15 à 24. On crée des widgets boutons et on les place dans la fenêtre. À noter que chacun de ces widgets appelle une
méthode différente, dont deux que nous avons créées dans la classe (.dessine_cercle() et .dessine_lignes()).
Ligne 26 à 28. Cette méthode renvoie une couleur au hasard sous forme de chaîne de caractères.
Lignes 30 à 40. On définit deux méthodes qui vont dessiner des paquets de 20 cercles (cas spécial d’une ellipse) ou 20
lignes aléatoires. Lors de la création de ces cercles et lignes, on ne les récupère pas dans une variable car on ne souhaite ni les
réutiliser ni changer leurs propriétés par la suite. Vous pourrez noter ici l’avantage de programmer avec une classe, le canvas
est directement accessible dans n’importe quelle méthode de la classe avec self.canv (pas besoin de le passer en argument
F IGURE 20.5 – Exemple 2 de canvas. ou de créer une variable globale).
20.6.2 Un canvas encapsulé dans une classe 20.6.3 Un canvas animé dans une classe
Voici un exemple un peu plus conséquent d’utilisation du widget canvas qui est inclus dans une classe. Il s’agit d’une Dans ce dernier exemple, nous allons illustrer la puissance du widget canvas en vous montrant que l’on peut animer les
application dans laquelle il y a une zone de dessin, un bouton dessinant des cercles, un autre des lignes et un dernier bouton objets se trouvant à l’intérieur. Nous allons également découvrir une technique intéressante, à savoir, comment « intercepter »
qui quitte l’application (figure 20.5). des clics de souris générés ou des touches pressées par l’utilisateur. L’application consiste en une « baballe » qui se déplace
Le code suivant crée une telle application : dans la fenêtre et dont on contrôle les propriétés à la souris (cf. figure 20.6). Vous pouvez télécharger le script ici 11 .
1 import tkinter as tk 1 """ Super appli baballe !!!
2 import random as rd 2
3
3 Usage :python tk_baballe . py
class AppliCanevas ( tk . Tk ): 4 - clic gauche : faire grossir la baballe
4
5 - clic droit : faire r é tr é cir la baballe
5 def __init__ ( self ): 6 - clic central : relance la baballe ( depuis le point du clic )
6 tk . Tk . __init__ ( self ) 7 dans une direction al é atoire
7 self . size = 500 8 - touche Esc : quitte l ' appli baballe
8 self . creer_widgets () 9 """
9 10
10 def creer_widgets ( self ): 11 import tkinter as tk
11 # cr é ation canevas 12 import random as rd
12 self . canv = tk . Canvas ( self , bg =" light gray " , height = self . size , 13
13 width = self . size ) 14 class AppliBaballe ( tk . Tk ):
14 self . canv . pack ( side = tk . LEFT ) 15 def __init__ ( self ):
15 # boutons 16 """ Constructeur de l ' application ."""
16 self . bouton_cercles = tk . Button ( self , text =" Cercle !" , 17 tk . Tk . __init__ ( self )
17 command = self . dessine_cercles ) 18 # Coord baballe .
18 self . bouton_cercles . pack ( side = tk . TOP ) 19 self .x , self . y = 200 , 200
20 # Rayon baballe .
19 self . bouton_lignes = tk . Button ( self , text =" Lignes !" , 21 self . size = 50
20 command = self . dessine_lignes ) 22 # Pas de deplacement .
21 self . bouton_lignes . pack () 23 self . dx , self . dy = 20 , 20
22 self . bouton_quitter = tk . Button ( self , text =" Quitter " , 24 # Cr é ation et packing du canvas .
23 command = self . quit ) 25 self . canv = tk . Canvas ( self , bg = ' light gray ' , height =400 , width =400)
24 self . bouton_quitter . pack ( side = tk . BOTTOM ) 26 self . canv . pack ()
25 27 # Cr é ation de la baballe .
26 def rd_col ( self ):
27 return rd . choice ((" black " , " red " , " green " , " blue " , " yellow " , " magenta " , 11. https://python.sdv.univ-paris-diderot.fr/data-files/tk_baballe.py
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 229 230 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
20.6. Le widget canvas Chapitre 20. Fenêtres graphiques et Tkinter Chapitre 20. Fenêtres graphiques et Tkinter 20.7. Pour aller plus loin
28 self . baballe = self . canv . create_oval ( self .x , self .y , de bouton, vous vous souvenez ? On l’appelle donc sans parenthèses ni arguments). On notera que tous ces événements sont
29 self . x + self . size ,
30 self . y + self . size , liés à des clics sur le canvas, mais il est possible de capturer des événements de souris sur d’autres types de widgets.
31 width =2 , fill =" blue ") Ligne 36. De même, on peut « intercepter » un événement lié à l’appui sur une touche, ici la touche Esc.
# Binding des actions .
32
33 self . canv . bind (" < Button -1 >" , self . incr )
Ligne 38. La méthode .move() est appelée, ainsi l’animation démarrera dès l’exécution du constructeur, donc peu après
34 self . canv . bind (" < Button -2 >" , self . boom ) l’instanciation de notre application (Ligne 86).
35 self . canv . bind (" < Button -3 >" , self . decr ) Lignes 40 à 58. On définit une méthode .move() qui va gérer le déplacement de la baballe avec des chocs élastiques sur
36 self . bind (" < Escape >" , self . stop )
37 # Lancer la baballe . les parois (et faire en sorte qu’elle ne sorte pas du canvas).
38 self . move () Lignes 55 et 56. On utilise la méthode .coords() de la classe Canvas, qui « met à jour » les coordonnées de n’importe
39
40 def move ( self ): quel objet dessiné dans le canvas (c’est-à-dire que cela déplace l’objet).
41 """ D é place la baballe ( appel é e it é rativement avec la m é thode after ).""" Ligne 58. Ici, on utilise une autre méthode spécifique des objets Tkinter. La méthode .after() rappelle une autre méthode
42 # Incr é mente coord baballe .
43 self . x += self . dx ou fonction (second argument) après un certain laps de temps (ici 50 ms, passé en premier argument). Ainsi la méthode
44 self . y += self . dy .move() se rappelle elle-même, un peu comme une fonction récursive. Toutefois, ce n’est pas une vraie fonction récursive
45 # V é rifier que la baballe ne sort pas du canvas ( choc é lastique ).
46 if self . x < 10: comme celle vue dans le chapitre 12 (exemple du calcul de factorielle), car Python ne conserve pas l’état de la fonction lors
47 self . dx = abs ( self . dx ) de l’appel de .after(). C’est comme si on avait un return, tout l’espace mémoire alloué à la méthode .move() est détruit
if self . x > 400 - self . size -10:
48
49 self . dx = - abs ( self . dx ) lorsque Python rencontre la méthode .after(). On obtiendrait un résultat similaire avec la boucle suivante :
50 if self . y < 10: 1 import time
51 self . dy = abs ( self . dy ) 2
52 if self . y > 400 - self . size -10: 3 ...
53 self . dy = - abs ( self . dy ) 4
54 # Mise à jour des coord . 5 while True :
55 self . canv . coords ( self . baballe , self .x , self .y , self . x + self . size , 6 move ()
56 self . y + self . size ) 7 time . sleep (0.05) # attendre 50 ms
57 # Rappel de move toutes les 50 ms .
58 self . after (50 , self . move ) Le temps de 50 ms donne 20 images (ou clichés) par seconde. Si vous diminuez ce temps, vous aurez plus d’images par
59
60 def boom ( self , mclick ): secondes et donc un « film » plus fluide.
61 """ Relance la baballe dans une direction al é atoire au point du clic .""" Ligne 60 à 66. On définit la méthode .boom() de notre classe qui on se souvient est appelée lors d’un événement clic cen-
62 self . x = mclick . x
63 self . y = mclick . y tral sur le canvas. Vous noterez qu’outre le self, cette fonction prend un autre argument que nous avons nommé ici mclick.
64 self . canv . create_text ( self .x , self .y , text =" Boom !" , fill =" red ") Il s’agit d’un objet spécial géré par Tkinter qui va nous donner des informations sur l’événement généré par l’utilisateur. Dans
self . dx = rd . choice ([ -30 , -20 , -10 , 10 , 20 , 30])
les lignes 62 et 63, cet objet mclick récupère les coordonnées où le clic a eu lieu grâce aux attributs mclick.x et mclick.y.
65
66 self . dy = rd . choice ([ -30 , -20 , -10 , 10 , 20 , 30])
67 Ces coordonnées sont réaffectées à la baballe pour la faire repartir de l’endroit du clic. Nous créons ensuite un petit texte dans
68 def incr ( self , lclick ):
69 """ Augmente la taille de la baballe .""" le canevas et affectons des valeurs aléatoires aux variables de déplacement pour faire repartir la baballe dans une direction
70 self . size += 10 aléatoire.
if self . size > 200:
Lignes 68 à 78. On a ici deux méthodes .incr() et .decr() appelées lors d’un clic gauche ou droit. Deux choses sont à
71
72 self . size = 200
73
noter : i) l’attribut self.size est modifié dans les deux fonctions, mais le changement de diamètre de la boule ne sera effectif
def decr ( self , rclick ):
dans le canvas que lors de la prochaine exécution de l’instruction self.canv.coords() (dans la méthode .move()) ; ii) de
74
75 """ Diminue la taille de la baballe ."""
76 self . size -= 10 même que pour la méthode .boom(), ces deux méthodes prennent un argument après le self (lclick ou rclick) récupérant
77 if self . size < 10:
78 self . size = 10 ainsi des informations sur l’événement de l’utilisateur. Même si on ne s’en sert pas, cet argument après le self est obligatoire
79
80 def stop ( self , esc ):
car il est imposé par la méthode .bind().
81 """ Quitte l ' application .""" Lignes 80 à 82. Cette méthode quitte l’application lorsque l’utilisateur fait un clic sur la touche Esc.
82 self . quit () Il existe de nombreux autres événements que l’on peut capturer et lier à des méthodes / fonctions callback. Vous trouverez
83
84 une liste complète ici 13 .
85 if __name__ == " __main__ ":
86 myapp = AppliBaballe ()
87 myapp . title (" Baballe !")
88 myapp . mainloop () 20.7 Pour aller plus loin
Lignes 19 à 23. Les coordonnées de la baballe, ses pas de déplacement, et sa taille sont créés en tant qu’attributs de notre
classe. Ainsi ils seront visibles partout dans la classe.
20.7.1 D’autres widgets
Lignes 25 à 31. Le canvas est ensuite créé et placé dans la fenêtre, puis on définit notre fameuse baballe. À noter, les Jusqu’à maintenant nous avons vu les widgets Button, Canvas, Label, mais il en existe bien d’autres. En voici la liste avec
coordonnées self.x et self.y de la baballe représentent en fait son côté « nord-ouest » (en haut à gauche, voir le point (x0 , une brève explication pour chacun :
y0 ) dans la documentation officielle 12 ). — Checkbutton : affiche des cases à cocher.
Lignes 33 à 35. Jusqu’à maintenant, nous avons utilisé des événements provenant de clics sur des boutons. Ici, on va — Entry : demande à l’utilisateur de saisir une valeur / une phrase.
« intercepter » des événements générés par des clics de souris sur le canvas et les lier à une fonction / méthode (comme — Listbox : affiche une liste d’options à choisir (comme dans la figure 20.1).
nous l’avions fait pour les clics sur des boutons avec l’option command=...). La méthode pour faire cela est .bind(), voilà — Radiobutton : implémente des « boutons radio ».
pourquoi on parle de event binding en anglais. Cette méthode prend en argument le type d’événement à capturer en tant — Menubutton et Menu : affiche des menus déroulants.
que chaîne de caractères avec un format spécial : par exemple "<Button-1>" correspond à un clic gauche de la souris (de — Message : affiche un message sur plusieurs lignes (extensions du widget Label).
même "<Button-2>" et "<Button-3>" correspondent aux clics central et droit respectivement). Le deuxième argument de — Scale : affiche une règle graduée pour que l’utilisateur choisisse parmi une échelle de valeurs.
la méthode .bind() est une méthode / fonction callback à appeler lors de la survenue de l’événement (comme pour les clics — Scrollbar : affiche des ascenseurs (horizontaux et verticaux).
12. http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/create_oval.html 13. http://effbot.org/tkinterbook/tkinter-events-and-bindings.htm
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 231 232 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
20.7. Pour aller plus loin Chapitre 20. Fenêtres graphiques et Tkinter Chapitre 20. Fenêtres graphiques et Tkinter 20.7. Pour aller plus loin
ttk, nous vous conseillons d’utiliser les widgets ttk en priorité, et pour ceux qui n’existent pas dans ttk, ceux de Tkinter (comme 3 class Application ( tk . Frame ):
4 def __init__ ( self , racine = None ):
Canvas qui n’existe que dans Tkinter). Vous pouvez importer le sous-module ttk de cette manière : import tkinter.ttk 5 tk . Frame . __init__ ( self , racine )
as ttk. 6 self . racine = racine
7 self . cre ate_widg ets ()
Vous pourrez alors utiliser les classes de widget de ttk (par exemple ttk.Button, etc.). Si vous souhaitez importer ttk et 8
9 def create_w idgets ( self ):
Tkinter, il suffit d’utiliser ces deux lignes : 10 self . label = tk . Label ( self . racine , text =" J ' adore Python !")
11 self . bouton = tk . Button ( self . racine , text =" Quitter " ,
1 import tkinter as tk 12 fg =" green " , command = self . quit )
2 import tkinter . ttk as ttk
13 self . label . pack ()
14 self . bouton . pack ()
15
Ainsi vous pourrez utiliser des widgets de Tkinter et de ttk en même temps. 16
if __name__ == " __main__ ":
Pour plus d’informations, vous pouvez consulter la documentation officielle de Python 16 , ainsi que la documentation très 17
18 racine = tk . Tk ()
complète du site du MNT 17 . 19 racine . title (" Ma Premi è re App : -)")
18. https://infohost.nmt.edu/tcc/help/pubs/tkinter/web/control-variables.html
14. http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html 19. http://effbot.org/tkinterbook/pack.htm
15. https://infohost.nmt.edu/tcc/help/pubs/tkinter/web/universal.html 20. http://effbot.org/tkinterbook/grid.htm
16. https://docs.python.org/3/library/tkinter.ttk.html 21. https://infohost.nmt.edu/tcc/help/pubs/tkinter/web/grid.html
17. http://infohost.nmt.edu/tcc/help/pubs/tkinter/web/ttk.html 22. http://effbot.org/tkinterbook/place.htm
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 233 234 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
20.7. Pour aller plus loin Chapitre 20. Fenêtres graphiques et Tkinter Chapitre 20. Fenêtres graphiques et Tkinter 20.7. Pour aller plus loin
20 app = Application ( racine ) Toutefois, même si cela « ne coûte rien », nous vous recommandons de ne pas mettre ces *args et **kwargs si vous n’en
21 racine . mainloop () avez pas besoin, comme nous vous l’avons montré dans les exemples de ce chapitre. Rappelons nous de la PEP 20 (cf. chapitre
Lignes 17 à 21. Commentons d’abord le programme principal : ici on crée la fenêtre principale dans l’instance racine 15 Bonnes Pratiques en programmation Python), les assertions « Simple is better than complex » ou « Sparse is better than
puis on instancie notre classe en passant racine en argument. dense » nous suggèrent qu’il est inutile d’ajouter des choses dont on ne se sert pas.
Lignes 4 et 5. Ici réside la principale différence par rapport à ce que nous vous avons montré dans ce chapitre : en ligne
4 on passe l’argument racine à notre constructeur, puis en ligne 5 on passe ce même argument racine lors de l’appel du Toujours préciser l’instance de la fenêtre principale
constructeur de la classe tk.Frame (ce qui était inutile lorsqu’on héritait de la classe Tk).
Tkinter est parfois surprenant. Dans le code suivant, on pourrait penser que celui-ci n’est pas fonctionnel :
Ligne 6. L’argument racine passé à la méthode .__init__() est finalement une variable locale. Comme il s’agit de
l’instance de notre fenêtre principale à passer à tous nos widgets, il faut qu’elle soit visible dans toute la classe. La variable 1 >>> import tkinter as tk
2 >>> bouton = tk . Button ( text =" Quitter ")
self.racine est ainsi créée afin d’être réutilisée dans d’autres méthodes. 3 >>> bouton . pack ()
Vous pourrez vous posez la question : « Pourquoi en ligne 4 l’argument par mot-clé racine=None prend la valeur None
par défaut ? ». Et bien, c’est parce que notre classe Application peut s’appeler sans passer d’instance de fenêtre Tk. Voici un Pour autant, cela fonctionne et on voit un bouton apparaître ! En fait, Tkinter va automatiquement instancier la fenêtre
exemple avec les lignes qui changent seulement (tout le reste est identique au code précédent) : principale, si bien qu’il n’est pas obligatoire de passer cette instance en argument d’un widget. À ce moment, on peut se de-
mander où est passé cette instance. Heureusement, Tkinter garde toujours une filiation des widgets avec les attributs .master
[...]
et .children :
1
2 class Application ( tk . Frame ):
3 def __init__ ( self , racine = None ): 1 >>> racine = bouton . master
4 tk . Frame . __init__ ( self ) 2 >>> racine
5 self . racine = racine 3 < tkinter . Tk object . >
6 [...] 4 >>> racine . children
7 [...] 5 { '! button ': < tkinter . Button object .! button >}
8 if __name__ == " __main__ ": 6 >>> bouton [" command "] = racine . destroy
9 app = Application ()
10 app . mainloop () Ligne 1. On « récupère » l’instance de la fenêtre principale dans la variable racine.
Les lignes 4 et 5 montrent que le bouton est un « enfant » de cette dernière.
Dans un tel cas, l’argument racine prend la valeur par défaut None lorsque la méthode .__init__() de notre classe
Enfin, ligne 6, on réassigne la destruction de la fenêtre lorsqu’on clique sur le bouton.
est exécutée. L’appel au constructeur de la classe Frame en ligne 4 instancie automatiquement une fenêtre Tk (car cela est
Ces attributs .master et .children existent pour tous widgets et sont bien pratiques lorsqu’on crée de grosses applica-
strictement obligatoire). Dans la suite du programme, cette instance de la fenêtre principale sera self.racine et il n’y aura
tions graphiques (où on utilise souvent des widgets parents contenant d’autres widgets enfants). Une autre source d’information
pas de changement par rapport à la version précédente. Cette méthode reste toutefois peu intuitive car cette instance de la
sur les widgets se trouvent dans les méthodes dont le nom commence par winfo. Par exemple, la méthode .winfo_toplevel()
fenêtre principale self.racine vaut finalement None !
renvoie la même information que l’attribut .master (une référence vers le widget parent).
Hériter de la classe Frame ou de la classe Tk sont deux manières tout à fait valides pour créer des applications Tkinter. Le
choix de l’une ou de l’autre relève plus de préférences que l’on acquiert en pratiquant, voire de convictions philosophiques
sur la manière de programmer. Toutefois, nous pensons qu’hériter de la classe tk.Tk est une manière plus générale et plus Conseil
compacte : tout ce qui concerne le fenêtrage Tkinter se situera dans votre classe Application, et le programme principal n’aura Même si cela est possible, nous vous conseillons de systématiquement préciser l’instance de la fenêtre principale lors de
qu’à instancier l’application et à lancer le gestionnaire d’événements (les choses seront ainsi mieux « partitionnées »). C’est la création de vos widgets.
donc la méthode que nous vous recommandons.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 235 236 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
20.8. Exercices Chapitre 20. Fenêtres graphiques et Tkinter Chapitre 20. Fenêtres graphiques et Tkinter 20.8. Exercices
20.8.2 Horloge
Sur la base de l’application précédente, faites une application qui affiche l’heure dans un label en se mettant à jour sur
l’heure de l’ordinateur une fois par seconde. Vous concevrez une méthode .mise_a_jour_heure() qui met à jour l’heure
dans le label et qui se rappelle elle-même toutes les secondes (n’oubliez pas la méthode .after(), cf. rubrique Un canvas
animé dans une classe ci-dessus). Pour cette mise à jour, vous pourrez utiliser la méthode .configure(), par exemple :
self.label.configure(text=heure) où heure est une chaîne de caractères représentant l’heure actuelle.
Le triangle de Sierpinski 35
est une fractale classique. On se propose ici de la dessiner avec un algorithme tiré du jeu du Le rendu final attendu est montré dans la figure 20.8. On utilisera un canevas de 400x400 pixels. Il y a aura un bouton «
chaos 36 . Celui-ci se décompose en pseudo-code de la façon suivante : Quitter » et un bouton « Launch ! » qui calculera et affichera 10000 points supplémentaires dans le triangle de Sierpinski.
27. https://wiki.python.org/moin/TkInter
28. https://infohost.nmt.edu/tcc/help/pubs/tkinter/web/index.html
20.8.5 Polygone de Sierpinski (exercice +++)
29. http://effbot.org/tkinterbook/
30. https://www.tutorialspoint.com/python/python_gui_programming.htm
Améliorer l’application précédente en proposant une liste de choix supplémentaire demandant à l’utilisateur de choisir le
31. https://github.com/Dvlv/Tkinter-By-Example nombre de sommets (de 3 à 10). Le programme calculera automatiquement la position des sommets. Pour prendre en main
32. https://pythonprogramming.net/tkinter-depth-tutorial-making-actual-program/ le widget Listbox, voici un code minimal qui pourra vous aider. Celui-ci contient une Listbox et permet d’afficher dans le
33. http://tkinter.fdex.eu/index.html terminal l’élément sélectionné. Nous vous conseillons de bien étudier le code ci-dessous et d’avoir résolu l’exercice précédent
34. https://inforef.be/swi/python.htm
35. https://fr.wikipedia.org/wiki/Triangle_de_Sierpi%C5%84ski
avant de vous lancer !
36. https://fr.wikipedia.org/wiki/Jeu_du_chaos 1 import tkinter as tk
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 237 238 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
20.8. Exercices Chapitre 20. Fenêtres graphiques et Tkinter
2
3 class MaListBox ( tk . Tk ):
4 def __init__ ( self ):
5 # Instanciation fen ê tre Tk .
6 tk . Tk . __init__ ( self )
7 self . listbox = tk . Listbox ( self , height =10 , width =4)
8 self . listbox . pack ()
9 # Ajout des items à la listbox ( entiers ).
for i in range (1 , 10+1):
10
11 # Utilisation de ma m é thode . insert ( index , element ) Chapitre 21
12 # Ajout de l ' entier i ( tk . END signifie en dernier ).
13 self . listbox . insert ( tk . END , i )
14 # Selection du premier é l é ment de listbox .
15 self . listbox . select_set (0)
16
17
18
# Liaison d ' une m é thode quand clic sur listbox .
self . listbox . bind (" < < ListboxSelect > >" , self . clic_listbox ) Remarques complémentaires
19 def clic_listbox ( self , event ):
20 # R é cup é ration du widget à partir de l ' objet event .
21 widget = event . widget
22 # R é cup é ration du choix s é lectionn é dans la listbox ( tuple ).
23 # Par exemple renvoie `(5 ,) ` si on a cliqu é sur `5 `.
24 selection = widget . curselection () 21.1 Différences Python 2 et Python 3
25 # R é cup é ration du nombre s é lectionn é ( d é j à un entier ).
26 choix_select = widget . get ( selection [0])
27 # Affichage . Python 3 est la version de Python qu’il faut utiliser.
28 print ( f " Le choix s é lectionn é est { choix_select } , " Néanmoins, Python 2 a été employé pendant de nombreuses années par la communauté scientifique et vous serez certai-
29 f " son type est { type ( choix_select )}")
30
nement confrontés à un programme écrit en Python 2. Voici quelques éléments pour vous en sortir :
31
32
33 if __name__ == " __main__ ":
34 app = MaListBox () 21.1.1 Le mot-clé print / la fonction print()
35 app . title (" MaListBox ")
36 app . mainloop () En Python 2 print est un mot-clé du langage (en anglais statement) au même titre que for, if, def, etc. Il s’utilise ainsi
sans parenthèse. Par exemple :
1 >>> print 12
20.8.6 Projet simulation d’un pendule 2 12
3 >>> print " girafe "
Vous souhaitez aller plus loin après ces exercices de « mise en jambe » ? Nous vous conseillons d’aller directement au 4 girafe
chapitre 22 Mini projets. Nous vous proposons de réaliser une application Tkinter qui simule le mouvement d’un pendule.
Par contre en Python 3, print() est une fonction. Ainsi, si vous n’utilisez pas de parenthèse, Python vous renverra une
En réalisant une application complète de ce genre, un peu plus conséquente, vous serez capable de construire vos propres
erreur :
applications.
1 >>> print 12
2 File " < stdin >" , line 1
3 print 12
4 ^
5 SyntaxError : Missing parentheses in call to ' print '
Faites très attention à cet aspect si vous programmez encore en Python 2, c’est une source d’erreur récurrente.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 239 240
21.1. Différences Python 2 et Python 3 Chapitre 21. Remarques complémentaires Chapitre 21. Remarques complémentaires 21.2. Gestion des exceptions
La fonction input() demande à l’utilisateur de saisir une chaîne de caractères. Cette chaîne de caractères est ensuite
Remarque transformée en nombre entier avec la fonction int().
Pour générer une liste d’entiers avec la fonction range() en Python 3, vous avez vu dans le chapitre 4 Listes qu’il suffit Si l’utilisateur ne rentre pas un nombre, voici ce qui se passe :
de l’associer avec la fonction list(). Par exemple : 1 >>> nb = int ( input (" Entrez un nombre entier : "))
2 Entrez un nombre entier : ATCG
1 >>> list ( range (10)) 3 Traceback ( most recent call last ):
2 [0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9] 4 File " < stdin >" , line 1 , in < module >
5 ValueError : invalid literal for int () with base 10: ' ATCG '
L’erreur provient de la fonction int() qui n’a pas pu convertir la chaîne de caractères "ATCG" en nombre entier, ce qui
est parfaitement normal. En termes plus techniques, on dira que « Python a levé une exception de type ValueError ». Eh oui
Remarque En Python 3, la fonction range() est ce qu’on appelle un générateur dans le sens où il y a de nombreux types d’exceptions différents (voir plus bas) ! Le nom de l’exception apparaît toujours comme le premier
elle génère un objet contenant une série de valeurs, utilisables une à la fois, par itération dans une boucle for. L’objet de type mot de la dernière ligne du message d’erreur. Si nous lancions ces lignes de code sous forme de script (du style python
range renvoyé par la fonction est quant à lui appelé itérateur. Si vous souhaitez en savoir un peu plus sur la différence entre script.py), cet exemple conduirait à l’arrêt de l’exécution du programme.
un générateur et un itérateur, vous pouvez consulter cette ressource 1 . Le jeu d’instructions try / except permet de tester l’exécution d’une commande et d’intervenir en cas de levée d’excep-
tion.
1 >>> try :
2 ... nb = int ( input (" Entrez un nombre entier : "))
21.1.4 Encodage et utf-8 3 ... except :
4 ... print (" Vous n ' avez pas entr é un nombre entier !")
En Python 3, vous pouvez utiliser des caractères accentués dans les commentaires ou dans les chaîne de caractères. 5 ...
6 Entrez un nombre entier : ATCG
Ce n’est pas le cas en Python 2. Si un caractère accentué est présent dans votre code, cela occasionnera une erreur de ce 7 Vous n ' avez pas entr é un nombre entier !
type lors de l’exécution de votre script :
Dans cette exemple, l’exception levée par la fonction int() (qui ne peut pas convertir "ATCG" en nombre entier) est
1 SyntaxError : Non - ASCII character '\ xc2 ' in file xxx on line yyy , but no encoding
2 declared ; see http :// python . org / dev / peps / pep -0263/ for details interceptée et déclenche l’affichage du message d’avertissement.
On peut ainsi redemander sans cesse un nombre entier à l’utilisateur, jusqu’à ce que celui-ci en rentre bien un.
Pour éviter ce genre de désagrément, ajoutez la ligne suivante en tout début de votre script : 1 >>> while True :
1 # coding : utf -8 2 ... try :
3 ... nb = int ( input (" Entrez un nombre entier : "))
Si vous utilisez un shebang (voir rubrique précédente), il faudra mettre la ligne # coding: utf-8 sur la deuxième ligne 4 ... print (" Le nombre est " , nb )
5 ... break
(la position est importante 2 ) de votre script : 6 ... except :
1. https://data-flair.training/blogs/python-generator-vs-iterator/ 3. https://fr.wikipedia.org/wiki/Syst%C3%A8me_de_gestion_d%27exceptions
2. http://www.python.org/dev/peps/pep-0263/ 4. https://en.wikipedia.org/wiki/Exception_handling
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 241 242 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
21.2. Gestion des exceptions Chapitre 21. Remarques complémentaires Chapitre 21. Remarques complémentaires 21.2. Gestion des exceptions
7 ... print (" Vous n ' avez pas entr é un nombre entier !") — Pa ailleurs, ne mettez pas trop de lignes dans le bloc du try. Dans un tel cas, il peut être très pénible de trouver la
8 ... print (" Essayez encore ") ligne qui a conduit à l’exécution du except. Pire encore, il se peut que des lignes que vous aviez prévues ne soient
9 ...
10 Entrez un nombre entier : ATCG pas exécutées ! Donc gardez des choses simples dans un premier temps, comme par exemple tester les conversions de
11 Vous n ' avez pas entr é un nombre entier !
12 Essayez encore type ou vérifier qu’un fichier existe bien et que vous pouvez l’ouvrir.
13 Entrez un nombre entier : toto
14 Vous n ' avez pas entr é un nombre entier !
15 Essayez encore
16 Entrez un nombre entier : 3.2 Il existe de nombreux types d’exception comme RuntimeError, TypeError, NameError, IOError, etc. Vous pouvez
17 Vous n ' avez pas entr é un nombre entier ! aller voir la liste complète 5 sur le site de Python. Nous avions déjà croisé des noms d’exception au chapitre 19 (Avoir la classe
18 Essayez encore
19 Entrez un nombre entier : 55 avec les objets) en regardant ce que contient le module builtins.
20 Le nombre est 55
1 >>> import builtins
>>> dir ( builtins )
Notez que dans cet exemple, l’instruction while True est une boucle infinie car la condition True est toujours vérifiée. 2
3 [ ' ArithmeticError ' , ' AssertionError ' , ' AttributeError ' , ' BaseException ' ,
L’arrêt de cette boucle est alors forcé par la commande break lorsque l’utilisateur a effectivement entré un nombre entier. 4 [...]
5 ' UserWarning ' , ' ValueError ' , ' Warning ' , ' ZeroDivisionError '
La gestion des exceptions est très utile dès lors que des données extérieures entrent dans un programme Python, que ce soit 6 [...]
directement par l’utilisateur (avec la fonction input()) ou par des fichiers. Cela est fondamental si vous distribuez votre code
à la communauté : si les utilisateurs ne connaissent pas Python, un message comme Vous n'avez pas entré un nombre Leur présence dans le module builtins signifie qu’elles font partie du langage lui même, au même titre que les fonctions
entier ! reste plus clair que ValueError: invalid literal for int() with base 10: 'ATCG'. de base comme range(), list(), etc.
Vous pouvez par exemple vérifier qu’un fichier a bien été ouvert. Avez-vous aussi remarqué que leur nom commence toujours par une majuscule et qu’il peut en contenir plusieurs à la
façon CamelCase ? Si vous avez bien lu le chapitre 15 Bonnes Pratiques, avez-vous deviné pourquoi ? Et bien, c’est parce
1 >>> nom = " toto . pdb "
2 >>> try : que les exceptions sont des classes. C’est très intéressant car il est ainsi possible d’utiliser l’héritage pour créer ses propres
3 ... with open ( nom , " r ") as fichier : exceptions à partir d’exceptions pré-existantes. Nous ne développerons pas cet aspect, mais en guise d’illustration, regardez
4 ... for ligne in fichier :
5 ... print ( ligne ) ce que renvoit un help() de l’exception OverflowError.
6 ... except :
7 ... print (" Impossible d ' ouvrir le fichier " , nom ) 1 >>> help ( OverflowError )
2 [...]
3 class OverflowError ( Ar it hm e ti cE rr or )
Si une erreur est déclenchée, c’est sans doute que le fichier n’existe pas à l’emplacement indiqué sur le disque ou que vous 4 | Result too large to be represented .
n’avez pas les droits pour le lire. 5 |
6 | Method resolution order :
Il est également possible de spécifier le type d’erreur à gérer. Le premier exemple que nous avons étudié peut s’écrire : 7 | OverflowError
1 >>> try : 8 | Arith me ti cE r ro r
2 ... nb = int ( input (" Entrez un nombre entier : ")) 9 | Exception
3 ... except ValueError : 10 | BaseException
4 ... print (" Vous n ' avez pas entr é un nombre entier !") 11 | object
5 ...
6 Entrez un nombre entier : ATCG L’exception OverflowError hérite de ArithmeticError, c’est-à-dire qu’OverflowError a été conçue à partir de
7 Vous n ' avez pas entr é un nombre entier !
ArithmeticError et en hérite de tous ses attributs.
Ici, on intercepte une exception de type ValueError, ce qui correspond bien à un problème de conversion avec int(). Un autre aspect très important que nous avons croisé au chapitre 19 est la possibilité de lever vous-même une exception
Attention, si vous précisez le type d’exception comme ValueError, le except ValueError n’empêchera pas la levée avec le mot-clé raise. Nous avions vu le code suivant :
d’une autre exception. 1 if valeur < 0:
2 raise ValueError (" Z ' avez d é j à vu une masse n é gative ? C ' est nawak ")
1 >>> try :
2 ... nb = int ( variable ) La ligne 2 lève une exception ValueError lorsque la variable valeur est négative. L’instruction raise est bien pratique
3 ... except ValueError :
4 ... print (" Vous n ' avez pas entr é un nombre entier !") lorsque vous souhaitez stopper l’exécution d’un programme si une variable ne se trouve pas dans le bon intervalle ou ne
5 ... contient pas la bonne valeur. Vous avez sans doute compris maintenant pourquoi on parlait de « levée » d’exception. . . Pour
6 Traceback ( most recent call last ):
7 File " < stdin >" , line 2 , in < module > les non anglophones, allez voir ce que signifie raise en anglais ;-) !
8 NameError : name ' variable ' is not defined Enfin, on peut aussi être très précis dans le message d’erreur. Observez la fonction download_page() qui, avec le module
Ici l’exception levée est de type NameError car variable n’existe pas. Alors que si vous mettez except tout court, cela urllib, télécharge un fichier sur internet.
intercepte n’importe quelle exception. 1 import urllib . request
2
— Nous vous conseillons vivement de toujours préciser le type d’exception dans vos except. Cela évite d’intercepter une 16 data , error = download_page (" https :// files . rcsb . org / download /1 BTA . pdb ")
17
exception que vous n’aviez pas prévue. Il est possible d’intercepter plusieurs types d’exceptions en passant un tuple à
except, par exemple : except (Exception1, Exception2). 5. https://docs.python.org/fr/3.7/library/exceptions.html#exceptions.TypeError
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 243 244 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
21.3. Shebang et /usr/bin/env python3 Chapitre 21. Remarques complémentaires Chapitre 21. Remarques complémentaires 21.4. Passage d’arguments avec *args et **kwargs
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 245 246 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
21.5. Un peu de transformée de Fourier avec NumPy Chapitre 21. Remarques complémentaires Chapitre 21. Remarques complémentaires 21.6. Sauvegardez votre historique de commandes
L’utilisation de la syntaxe *args et **kwargs est très classique dans le module Tkinter présenté dans le chapitre 20. 1 >>> print (" hello ")
2 hello
Enfin, il est possible d’utiliser ce mécanisme d’empaquetage / désempaquetage (packing / unpacking) dans l’autre sens : 3 >>> a = 22
4 >>> a = a + 11
1 >>> def fct (a , b , c ): 5 >>> print ( a )
2 ... print (a ,b , c ) 6 33
3 ... 7 >>> import readline
4 >>> t = ( -5 ,6 ,7) 8 >>> readline . w r i t e _ h i s t o r y _ f i l e ()
5 >>>
6 >>> fct (* t ) Quittez Python. L’historique de toutes vos commandes est dans votre répertoire personnel, dans le fichier .history.
7 -5 6 7
Relancez l’interpréteur Python.
Avec la syntaxe *t on désempaquette le tuple à la volée lors de l’appel à la fonction. Cela est aussi possible avec un 1 >>> import readline
dictionnaire : 2 >>> readline . r e a d _ h i s t o r y _ f i l e ()
1 >>> def fct (x , y , z ): Vous pouvez accéder aux commandes de la session précédente avec la flèche du haut de votre clavier. D’abord les com-
... print (x , y , z )
2
3 ... mandes readline.read_history_file() et import readline de la session actuelle, puis print(a), a = a + 11, a =
4 >>> dico = { 'x ': -1 , 'y ': -2 , 'z ': -3} 22. . .
5 >>> fct (** dico )
6 -1 -2 -3
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 247 248 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
Chapitre 22. Mini-projets 22.2. Accompagnement pas à pas
Chapitre 22
Mini-projets
Dans ce chapitre, nous vous proposons quelques scénarios pour développer vos compétences en Python et mettre en œuvre
les concepts que vous avez rencontrés dans les chapitres précédents.
On se propose de réaliser une simulation d’un pendule simple 6 en Tkinter. Un pendule simple est représenté par une
masse ponctuelle (la boule du pendule) reliée à un pivot immobile par une tige rigide et sans masse. On néglige les effets 22.2 Accompagnement pas à pas
1. https://python.sdv.univ-paris-diderot.fr/data-files/english-common-words.txt
2. https://python.sdv.univ-paris-diderot.fr/data-files/human-proteome.fasta Vous trouverez ci-après les différentes étapes pour réaliser les mini-projets proposés. Prenez le temps de bien comprendre
3. https://www.uniprot.org/help/human_proteome une étape avant de passer à la suivante.
4. https://python.sdv.univ-paris-diderot.fr/data-files/NC_001133.gbk
5. https://www.ncbi.nlm.nih.gov/nuccore/NC_001133 7. https://en.wikipedia.org/wiki/Pendulum_(mathematics)#math_Eq._1
6. https://fr.wikipedia.org/wiki/Pendule_simple 8. https://en.wikipedia.org/wiki/Euler_method
249 250 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
22.2. Accompagnement pas à pas Chapitre 22. Mini-projets Chapitre 22. Mini-projets 22.2. Accompagnement pas à pas
ou
À la pêche aux mots
1 gene <2480.. >2707
Écrivez maintenant la fonction search_words_in_proteome() qui prend en argument la liste de mots et le dictionnaire et les gènes antisens (ou encore complémentaires) de cette façon :
contenant les séquences des protéines et qui va compter le nombre de séquences dans lesquelles un mot est présent. Cette
1 gene complement (5 5979. .569 35)
fonction renverra un dictionnaire dont les clefs sont les mots et les valeurs le nombre de séquences qui contiennent ces mots.
La fonction affichera également le message suivant pour les mots trouvés dans le protéome : ou
1 ACCESS found in 1 sequences 1 gene complement ( <13363.. >13743)
2 ACID found in 38 sequences
3 ACT found in 805 sequences Les valeurs numériques séparées par .. indiquent la position du gène dans le génome (numéro de la première base, numéro
4 [...] de la dernière base).
Cette étape prend quelques minutes. Soyez patient.
Remarque
Et le mot le plus fréquent est. . . Le symbole < indique un gène partiel sur l’extrémité 5’, c’est-à-dire que le codon START correspondant est incomplet.
Respectivement, le symbole > désigne un gène partiel sur l’extrémité 3’, c’est-à-dire que le codon STOP correspondant est
Pour terminer, écrivez maintenant la fonction find_most_frequent_word() qui prend en argument le dictionnaire ren- incomplet. Pour plus de détails, consultez la documentation du NCBI sur les délimitations des gènes 12 . Nous vous proposons
voyé par la précédente fonction search_words_in_proteome() et qui affiche le mot trouvé dans le plus de protéines, ainsi ici d’ignorer ces symboles > et <.
que le nombre de séquences dans lesquelles il a été trouvé, sous la forme :
1 = > xxx found in yyy sequences
Repérez ces différents gènes dans le fichier NC_001133.gbk. Pour récupérer ces lignes de gènes il faut tester si la ligne
9. https://python.sdv.univ-paris-diderot.fr/data-files/english-common-words.txt commence par
10. https://python.sdv.univ-paris-diderot.fr/data-files/human-proteome.fasta
11. https://www.uniprot.org/help/human_proteome 12. https://www.ncbi.nlm.nih.gov/Sitemap/samplerecord.html#BaseSpanB
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 251 252 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
22.2. Accompagnement pas à pas Chapitre 22. Mini-projets Chapitre 22. Mini-projets 22.2. Accompagnement pas à pas
1 gene Pour vous faciliter le travail, ne travaillez que sur des séquences en minuscule.
(c’est-à-dire 5 espaces, suivi du mot gene, suivi de 12 espaces). Pour savoir s’il s’agit d’un gène sur le brin direct ou Testez cette fonction avec les séquences atcg, AATTCCGG et gattaca.
complémentaire, il faut tester la présence du mot complement dans la ligne lue.
Ensuite si vous souhaitez récupérer la position de début et de fin de gène, nous vous conseillons d’utiliser la fonction Écriture d’un fichier FASTA
replace() et de ne garder que les chiffres et les . Par exemple
1 gene <2480.. >2707 Toujours dans le même script, ajoutez la fonction ecrit_fasta() qui prend en argument un nom de fichier (sous forme
de chaîne de caractères), un commentaire (sous forme de chaîne de caractères) et une séquence (sous forme de chaîne de
sera transformé en caractères) et qui écrit un fichier FASTA. La séquence sera à écrire sur des lignes ne dépassant pas 80 caractères.
1 2480..2707
Pour rappel, un fichier FASTA suit le format suivant :
Enfin, avec la méthode .split() vous pourrez facilement récupérer les deux entiers de début et de fin de gène. 1 > commentaire
Dans le même script genbank2fasta.py, ajoutez la fonction recherche_genes() qui prend en argument le contenu du 2 sequence sur une ligne de 80 caract è res maxi
3 suite de la s é quence . . . . . . . . . . . . . . . . . . . . . . .
fichier (sous la forme d’une liste de lignes) et qui renvoie la liste des gènes. 4 suite de la s é quence . . . . . . . . . . . . . . . . . . . . . . .
Chaque gène sera lui-même une liste contenant le numéro de la première base, le numéro de la dernière base et une chaîne 5 ...
de caractère "sens" pour un gène sens et "antisens" pour un gène antisens.
Testez cette fonction avec :
Testez cette fonction avec le fichier GenBank NC_001133.gbk et affichez le nombre de gènes trouvés, ainsi que le nombre
— nom de fichier : test.fasta
de gènes sens et antisens.
— commentaire : mon commentaire
— séquence : atcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcga
Extraction de la séquence nucléique du génome
La taille du génome est indiqué sur la première ligne d’un fichier GenBank. Trouvez la taille du génome stocké dans le
Extraction des gènes
fichier NC_001133.gbk.
Dans un fichier GenBank, la séquence du génome se trouve entre les lignes Toujours dans le même script, ajoutez la fonction extrait_genes() qui prend en argument la liste des gènes, la sé-
1 ORIGIN quence nucléotidique complète (sous forme d’une chaîne de caractères) et le nom de l’organisme (sous forme d’une chaîne de
caractères) et qui pour chaque gène :
et
— extrait la séquence du gène dans la séquence complète ;
//
— prend la séquence complémentaire inverse (avec la fonction construit_comp_inverse() si le gène est antisens ;
1
Trouvez dans le fichier NC_001133.gbk la première et dernière ligne de la séquence du génome. — enregistre le gène dans un fichier au format FASTA (avec la fonction ecrit_fasta()) ;
Pour récupérer les lignes contenant la séquence, nous vous proposons d’utiliser un algorithme avec un drapeau is_dnaseq — affiche à l’écran le numéro du gène et le nom du fichier FASTA créé.
(qui vaudra True ou False). Voici l’algorithme proposé en pseudo-code : La première ligne des fichiers FASTA sera de la forme :
is_dnaseq <- False
>nom - organisme | num é ro - du - g è ne | d é but | fin | sens ou antisens
1
2 Lire chaque ligne du fichier gbk 1
Au début ce drapeau aura la valeur False. Ensuite, quand il se mettra à True, on pourra lire les lignes contenant la
séquence, puis quand il se remettra à False on arrêtera. Assemblage du script final
Une fois la séquence récupérée, il suffira d’éliminer les chiffres, retours chariots et autres espaces (Conseil : calculer la
Pour terminer, modifiez le script genbank2fasta.py de façon à ce que le fichier GenBank à analyser (dans cet exemple
longueur de la séquence et comparer la à celle indiquée dans le fichier gbk).
NC_001133.gbk), soit entré comme argument du script.
Toujours dans le même script genbank2fasta.py, ajoutez la fonction extrait_sequence() qui prend en argument
le contenu du fichier (sous la forme de liste de lignes) et qui renvoie la séquence nucléique du génome (dans une chaîne de Vous afficherez un message d’erreur si :
caractères). La séquence ne devra pas contenir d’espaces, ni de chiffres ni de retours chariots. — le script genbank2fasta.py est utilisé sans argument,
Testez cette fonction avec le fichier GenBank NC_001133.gbk et affichez le nombre de bases de la séquence extraite. — le fichier fourni en argument n’existe pas.
Vérifiez que vous n’avez pas fait d’erreur en comparant la taille de la séquence extraite avec celle que vous avez trouvée dans Pour vous aider, n’hésitez pas à jeter un œil aux descriptions des modules sys et os dans le chapitre 8 Modules.
le fichier GenBank. Testez votre script ainsi finalisé.
Bravo, si vous êtes arrivés jusqu’à cette étape.
Construction d’une séquence complémentaire inverse
Toujours dans le même script, ajoutez la fonction construit_comp_inverse() qui prend en argument une séquence 22.2.3 genbank2fasta (avec expressions régulières)
d’ADN sous forme de chaîne de caractères et qui renvoie la séquence complémentaire inverse (également sous la forme d’une
chaîne de caractères). Ce projet consiste à écrire un convertisseur de fichier, du format GenBank au format FASTA. L’annexe A Quelques formats
On rappelle que construire la séquence complémentaire inverse d’une séquence d’ADN consiste à : de données rencontrés en biologie rappelle les caractéristiques de ces deux formats de fichiers.
— Prendre la séquence complémentaire. C’est-à-dire à remplacer la base a par la base t, t par a, c par g et g par c. Le jeu de données avec lequel nous allons travailler est le fichier GenBank du chromosome I de la levure du boulanger
— Prendre l’inverse. C’est-à-dire à que la première base de la séquence complémentaire devient la dernière base et Saccharomyces cerevisiae. Les indications pour le télécharger sont indiqués dans la description du projet.
réciproquement, la dernière base devient la première. Dans cette rubrique, nous allons réaliser ce projet avec des expressions régulières en utilisant le module re.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 253 254 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
22.2. Accompagnement pas à pas Chapitre 22. Mini-projets Chapitre 22. Mini-projets 22.2. Accompagnement pas à pas
Lecture du fichier Trouvez dans le fichier NC_001133.gbk la première et dernière ligne de la séquence du génome.
Construisez une expression régulière pour extraire du fichier GenBank les lignes correspondantes à la séquence du génome.
Créez un script genbank2fasta.py et créez la fonction lit_fichier() qui prend en argument le nom du fichier et qui
renvoie le contenu du fichier sous forme d’une liste de lignes, chaque ligne étant elle-même une chaîne de caractères. Modifiez ces expressions régulières pour que la séquence puisse être facilement extraite.
Testez cette fonction avec le fichier GenBank NC_001133.gbk et affichez le nombre de lignes lues. Toujours dans le même script, ajoutez la fonction extrait_sequence() qui prend en argument le contenu du fichier
(sous la forme de liste de lignes) et qui renvoie la séquence nucléique du génome (dans une chaîne de caractères). La séquence
ne devra pas contenir d’espaces.
Extraction du nom de l’organisme
Testez cette fonction avec le fichier GenBank NC_001133.gbk et affichez le nombre de bases de la séquence extraite.
Dans le même script, ajoutez la fonction extrait_organisme() qui prend en argument le contenu du fichier précédem- Vérifiez que vous n’avez pas fait d’erreur en comparant la taille de la séquence extraite avec celle que vous avez trouvée dans
ment obtenu avec la fonction lit_fichier() (sous la forme d’une liste de lignes) et qui renvoie le nom de l’organisme. le fichier GenBank.
Utilisez de préférence une expression régulière.
Testez cette fonction avec le fichier GenBank NC_001133.gbk et affichez le nom de l’organisme.
Construction d’une séquence complémentaire inverse
Recherche des gènes Toujours dans le même script, ajoutez la fonction construit_comp_inverse() qui prend en argument une séquence
d’ADN sous forme de chaîne de caractères et qui renvoie la séquence complémentaire inverse (également sous la forme d’une
Dans le fichier GenBank, les gènes sens sont notés de cette manière :
chaîne de caractères).
1 gene 58..272
On rappelle que construire la séquence complémentaire inverse d’une séquence d’ADN consiste à :
ou — Prendre la séquence complémentaire. C’est-à-dire à remplacer la base a par la base t, t par a, c par g et g par c.
1 gene <2480.. >2707 — Prendre l’inverse. C’est-à-dire à que la première base de la séquence complémentaire devient la dernière base et
réciproquement, la dernière base devient la première.
et les gènes antisens de cette façon : Pour vous faciliter le travail, ne travaillez que sur des séquences en minuscule.
1 gene complement (55979..569 35) Testez cette fonction avec les séquences atcg, AATTCCGG et gattaca.
ou
1 gene complement ( <13363.. >13743) Écriture d’un fichier FASTA
Les valeurs numériques séparées par .. indiquent la position du gène dans le génome (numéro de la première base, numéro
Toujours dans le même script, ajoutez la fonction ecrit_fasta() qui prend en argument un nom de fichier (sous forme
de la dernière base).
de chaîne de caractères), un commentaire (sous forme de chaîne de caractères) et une séquence (sous forme de chaîne de
caractères) et qui écrit un fichier FASTA. La séquence sera à écrire sur des lignes ne dépassant pas 80 caractères.
Remarque Pour rappel, un fichier FASTA suit le format suivant :
Le symbole < indique un gène partiel sur l’extrémité 5’, c’est-à-dire que le codon START correspondant est incomplet.
Respectivement, le symbole > désigne un gène partiel sur l’extrémité 3’, c’est-à-dire que le codon STOP correspondant est 1 > commentaire
2 sequence sur une ligne de 80 caract è res maxi
incomplet. Pour plus de détails, consultez la documentation du NCBI sur les délimitations des gènes 13 . 3 suite de la s é quence . . . . . . . . . . . . . . . . . . . . . . .
4 suite de la s é quence . . . . . . . . . . . . . . . . . . . . . . .
5 ...
Repérez ces différents gènes dans le fichier NC_001133.gbk. Construisez deux expressions régulières pour extraire du Testez cette fonction avec :
fichier GenBank les gènes sens et les gènes antisens. — nom de fichier : test.fasta
Modifiez ces expressions régulières pour que les numéros de la première et de la dernière base puissent être facilement — commentaire : mon commentaire
extraits. — séquence : atcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcgatcga
Dans le même script genbank2fasta.py, ajoutez la fonction recherche_genes() qui prend en argument le contenu du
fichier (sous la forme d’une liste de lignes) et qui renvoie la liste des gènes.
Chaque gène sera lui-même une liste contenant le numéro de la première base, le numéro de la dernière base et une chaîne Extraction des gènes
de caractère "sens" pour un gène sens et "antisens" pour un gène antisens.
Testez cette fonction avec le fichier GenBank NC_001133.gbk et affichez le nombre de gènes trouvés, ainsi que le nombre Toujours dans le même script, ajoutez la fonction extrait_genes() qui prend en argument la liste des gènes, la sé-
de gènes sens et antisens. quence nucléotidique complète (sous forme d’une chaîne de caractères) et le nom de l’organisme (sous forme d’une chaîne de
caractères) et qui pour chaque gène :
Extraction de la séquence nucléique du génome — extrait la séquence du gène dans la séquence complète ;
— prend la séquence complémentaire inverse (avec la fonction construit_comp_inverse() si le gène est antisens ;
La taille du génome est indiqué sur la première ligne d’un fichier GenBank. Trouvez la taille du génome stocké dans le — enregistre le gène dans un fichier au format FASTA (avec la fonction ecrit_fasta()) ;
fichier NC_001133.gbk. — affiche à l’écran le numéro du gène et le nom du fichier fasta créé.
Dans un fichier GenBank, la séquence du génome se trouve entre les lignes La première ligne des fichiers FASTA sera de la forme :
1 ORIGIN
1 >nom - organisme | num é ro - du - g è ne | d é but | fin | sens ou antisens
et
Le numéro du gène sera un numéro consécutif depuis le premier gène jusqu’au dernier. Il n’y aura pas de différence de
1 //
numérotation entre les gènes sens et les gènes antisens.
13. https://www.ncbi.nlm.nih.gov/Sitemap/samplerecord.html#BaseSpanB Testez cette fonction avec le fichier GenBank NC_001133.gbk.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 255 256 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
22.2. Accompagnement pas à pas Chapitre 22. Mini-projets Chapitre 22. Mini-projets 22.2. Accompagnement pas à pas
F = ma
Cette loi est exprimée ici dans le système de coordonnées cartésiennes (le plan à 2 dimensions). La force F et l’accélération
a sont des vecteurs dont les composantes sont respectivement (Fx , Fy ) et (ax , ay ). La force F correspond à la somme vectorielle
14. https://fr.wikipedia.org/wiki/Pendule_simple
15. https://en.wikipedia.org/wiki/Pendulum_(mathematics)
16. https://fr.wikipedia.org/wiki/Lois_du_mouvement_de_Newton
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 257 258 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
22.2. Accompagnement pas à pas Chapitre 22. Mini-projets Chapitre 22. Mini-projets 22.2. Accompagnement pas à pas
de T et P. La tige du pendule étant rigide, le mouvement de la boule est restreint sur le cercle de rayon égal à la longueur
L de la tige (dessiné en pointillé). Ainsi, seule la composante tangentielle de l’accélération a sera prise en compte dans ce
mouvement. Comment la calculer ? La force de tension T étant orthogonale au mouvement du pendule, celle-ci n’aura pas
d’effet. De même, la composante orthogonale mgcosθ due au poids P n’aura pas d’effet non plus. Au final, on ne prendra en
compte que la composante tangentielle due au poids, c’est-à-dire mgsinθ (cf. figure 22.3). Au final, on peut écrire l’expression
suivante en raisonnant sur les valeurs scalaires :
F = ma = −mgsinθ
Le signe − dans cette formule est très important. Il indique que l’accélération s’oppose systématiquement à θ . Si le
pendule se balance vers la droite et que θ devient plus positif, l’accélération tendra toujours à faire revenir la boule dans
l’autre sens vers sa position d’équilibre à θ = 0. On peut faire un raisonnement équivalent lorsque le pendule se balance vers
la gauche et que θ devient plus négatif.
Si on exprime l’accélération en fonction de θ , on trouve ce résultat qui peut sembler peu intuitif au premier abord :
a = −gsinθ
Le mouvement du pendule ne dépend pas de sa masse !
Idéalement, nous souhaiterions résoudre cette équation en l’exprimant en fonction de θ seulement. Cela est possible en
reliant θ à la longueur effective de l’arc s parcourue par le pendule :
s = θL
Pour bien comprendre cette formule, souvenez-vous de la formule bien connue du cercle l = 2πr (où l est la circonférence,
et r le rayon) ! Elle relie la valeur de θ à la distance de l’arc entre la position actuelle de la boule et l’origine (à θ = 0). On
peut donc exprimer la vitesse du pendule en dérivant s par rapport au temps t :
ds dθ
v= =L
dt dt
On peut aussi exprimer l’accélération a en dérivant l’arc s deux fois par rapport à t :
d2s d2θ
a= =L 2
dt 2 dt
A nouveau, cette dernière formule exprime l’accélération de la boule lorsque le mouvement de celle-ci est restreint sur le
cercle pointillé. Si la tige n’était pas rigide, l’expression serait différente.
Si on remplace a dans la formule ci-dessus, on trouve :
d2θ
L = −gsinθ
dt 2
Soit en remaniant, on trouve l’équation différentielle en θ décrivant le mouvement du pendule :
d2θ g
+ sinθ = 0
dt 2 L
Dans la section suivante, nous allons voir comment résoudre numériquement cette équation différentielle.
F IGURE 22.3 – Caractérisation géométrique d’un pendule simple.
d2θ g
aθ (t) = (t) = − sinθ (t)
dt 2 L
17. https://en.wikipedia.org/wiki/Numerical_methods_for_ordinary_differential_equations
18. https://en.wikipedia.org/wiki/Semi-implicit_Euler_method
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 259 260 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
22.2. Accompagnement pas à pas Chapitre 22. Mini-projets Chapitre 22. Mini-projets 22.2. Accompagnement pas à pas
L’astuce sera de calculer ensuite la vitesse angulaire au pas suivant t + δt grâce à la relation :
dθ
(t + δt) ≈ vθ (t) + aθ (t) × δt
vθ (t + δt) =
dt
Cette équation est ni plus ni moins qu’un remaniement de la définition de l’accélération, à savoir, la variation de vitesse
par rapport à un temps. Cette vitesse vθ (t + δt) permettra au final de calculer θ au temps t + δt (c’est-à-dire ce que l’on
cherche !) :
L’initialisation des valeurs de theta et dtheta est très importante car elle détermine le comportement du pendule. Nous F IGURE 22.4 – Application pendule.
avons choisi ici d’avoir une vitesse angulaire nulle et un angle de départ du pendule θ = π/4 rad = 45 deg. Le pas dt est
également très important, c’est lui qui déterminera l’erreur faite sur l’intégration de l’équation différentielle. Plus ce pas est
petit, plus on est précis, mais plus le calcul sera long. Ici, on choisit un pas dt de 0.05 s qui constitue un bon compromis. Constructeur de l’application en tkinter
À ce stade, vous avez tous les éléments pour tester votre pendule. Essayez de réaliser un petit programme python pendule_basic.py
Nous allons maintenant construire l’application tkinter en vous guidant pas à pas. Il est bien sûr conseillé de relire le
qui utilise les conditions initiales ci-dessus et simule le mouvement du pendule. A la fin de cette rubrique, nous proposons
chapitre 20 sur tkinter avant de vous lancer dans cette partie.
une solution en langage algorithmique. Essayez dans un premier temps de le faire vous-même. A chaque pas, le programme
Comme expliqué largement dans le chapitre 20, nous allons construire l’application avec une classe. Le programme prin-
écrira le temps t et l’angle θ dans un fichier pendule_basic.dat. Dans les équations, θ doit être exprimé en radian, mais
cipal sera donc très allégé et se contentera d’instancier l’application, puis de lancer le gestionnaire d’événements :
nous vous conseillons de convertir cet angle en degré dans le fichier (plus facile à comprendre pour un humain !). Une fois ce
1 if __name__ == " __main__ ":
fichier généré, vous pourrez observer le graphe correspondant avec matplotlib en utilisant le code suivant : 2 """ Programme principal ( instancie la classe principale , donne un
1 import matplotlib . pyplot as plt 3 titre et lance le gestionnaire d ' é v é nements )
2 import numpy as np 4 """
3 5 app_pendule = AppliPendule ()
4 # la fonction np . genfromtxt () renvoie un array à 2 dim 6 app_pendule . title (" Pendule ")
5 array_data = np . genfromtxt (" pendule_basic . dat ") 7 app_pendule . mainloop ()
6 # col 0: t , col 1: theta
7 t = array_data [: ,0]
8 theta = array_data [: ,1]
Ensuite, nous commençons par écrire le constructeur de la classe. Dans ce constructeur, nous aurons une section initialisant
9 toutes les variables utilisées pour simuler le pendule (cf. rubrique précédente), puis, une autre partie générant les widgets et
10 # plot
11 plt . figure ( figsize =(8 ,8))
tous les éléments graphiques. Nous vous conseillons vivement de bien les séparer, et surtout de mettre des commentaires
12 mini = min ( theta ) * 1.2 pour pouvoir s’y retrouver. Voici un « squelette » pour vous aider :
13 maxi = max ( theta ) * 1.2
14 plt . xlim (0 , max ( t )) 1 class AppliPendule ( tk . Tk ):
15 plt . ylim ( mini , maxi ) 2 def __init__ ( self ):
3 # instanciation de la classe Tk
16 plt . xlabel (" t ( s )")
4 tk . Tk . __init__ ( self )
17 plt . ylabel (" theta ( deg )") 5 # ici vous pouvez d é finir toutes les variables
18 plt . plot (t , theta ) 6 # concernant la physique du pendule
19 plt . savefig (" pendule_basic . png ") 7 self . theta = np . pi / 4 # valeur intiale theta
8 self . dtheta = 0 # vitesse angulaire initiale
Si vous observez une sinusoïde, bravo, vous venez de réaliser votre première simulation de pendule ! Vous avez maintenant 9 [...]
le « squelette » de votre « moteur » de simulation. N’hésitez pas à vous amuser avec d’autres conditions initiales. Ensuite vous 10 self . g = 9.8 # cst g r a v i ta t i o n ne l l e en m / s ^2
11 [...]
pourrez passer à la rubrique suivante. 12 # ici vous pouvez construire l ' application graphique
Si vous avez bloqué dans l’écriture de la boucle, voici à quoi elle pourrait ressembler en langage algorithmique : 13 self . canv = tk . Canvas ( self , bg = ' gray ' , height =400 , width =400)
14 # cr é ation d ' un boutton demarrer , arreter , quitter
1 tant qu ' on n ' arr ê te pas le pendule : 15 # penser à placer les widgets avec . pack ()
2 # acc angulaire au tps t ( en rad / s ^2) 16 [...]
3 d2theta <- -( g / L ) * sin ( theta )
4 # v angulaire mise à jour de t -> t + dt
5 dtheta <- dtheta + d2theta * dt La figure 22.4 vous montre un aperçu de ce que l’on voudrait obtenir.
6 # theta mis à jour de t -> t + dt Pour le moment, vous pouvez oublier la réglette fixant la valeur initiale de θ , les labels affichant la valeur de θ et vθ ainsi
7 theta <- theta + dtheta * dt
8 # t mis à jour que les points violets « laissés en route » par le pendule. De même, nous dessinerons le pivot, la boule et la tige plus tard. A
9 t <- t + dt
10 # mettre à jour l ' affichage ce stade, il est fondamental de tout de suite lancer votre application pour vérifier que les widgets sont bien placés. N’oubliez
11 a f f i c h e r _ p o s i t i o n _ p e n d u l e (t , theta ) pas, un code complexe se teste au fur et à mesure lors de son développement.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 261 262 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
22.2. Accompagnement pas à pas Chapitre 22. Mini-projets Chapitre 22. Mini-projets 22.3. Scripts de correction
Conseil : pour éviter un message d’erreur si toutes les méthodes n’existe pas encore, vous pouvez indiquer command=self.quit — btn1 = tk.Button(self, text="Quitter", command=self.quit)
pour chaque bouton (vous le changerez après). — btn2 = tk.Button(self, text="Demarrer", command=self.start)
— btn3 = tk.Button(self, text="Arrêter", command=self.stop)
Créations des dessins dans le canvas Ici, self.start() et self.stop() sont des méthodes que l’on doit créer, self.quit() pré-existe lorsque la fenêtre
tkinter est créée.
Le pivot et la boule pourront être créés avec la méthode .create_oval(), la tige le sera avec la méthode .create_line(). Nous vous proposons ici une stratégie inspirée du livre de Gérard Swinnen 19 . Créons d’abord un attribut d’instance
Pensez à créer des variables pour la tige et la boule lors de l’instanciation car celles-ci bougeront par la suite. self.is_moving dans le constructeur. Celui-ci va nous servir de « drapeau » pour définir le mouvement du pendule. Il
Comment placer ces éléments dans le canvas ? Vous avez remarqué que lors de la création de ce dernier, nous avons fixé contiendra un entier positif ou nul. Lorsque ce drapeau sera égal à 0, le pendule sera immobile. Lorsqu’il sera > 0, le pendule
une dimension de 400 × 400 pixels. Le pivot se trouve au centre, c’est-à-dire au point (200, 200) . Pour la tige et la boule il sera en mouvement. Ainsi :
sera nécessaire de connaître la position de la boule dans le repère du canvas. Or, pour l’instant, nous définissons la position — la méthode .start() ajoutera 1 à self.is_moving. Si self.is_moving est égal à 1 alors la méthode self.move()
de la boule avec l’angle θ . Il va donc nous falloir convertir θ en coordonnées cartésiennes (x, y) dans le repère mathématique sera appelée ;
défini dans la figure 22.3, puis dans le repère du canvas (xc , yc ) (cf. rubrique suivante). — la méthode .stop() mettra la valeur de self.is_moving à 0.
Puisque .start() ajoute 1 à self.is_moving, le premier clic sur le bouton « Démarrer » appelera la méthode .move()
Conversion de θ en coordonnées (x, y) Cette étape est relativement simple si on considère le pivot comme le centre du car self.is_moving vaudra 1. Si l’utilisateur appuie une deuxième fois sur le bouton « Démarrer », self.is_moving
repère. Avec les fonctions trigonométriques sin() et cos(), vous pourrez calculer la position de la boule (cf. exercice sur la vaudra 2 mais n’appellera pas .move() une deuxième fois ; cela sera vrai pour tout clic ultérieur de l’utilisateur sur ce bouton.
spirale dans le chapitre 7). Faites attention toutefois aux deux aspects suivants : Cette astuce évite des appels concurrents de la méthode .move().
— la trajectoire de la boule suit les coordonnées d’un cercle de rayon L (si on choisit L = 1 m, ce sera plus simple) ;
— nous sommes décalés par rapport au cercle trigonométrique classique ; si on considère L = 1 m : Le coeur du programme : la méthode .move()
— quand θ = 0, on a le point (0, −1) (pendule en bas) ;
— quand θ = +π/2 = 90 deg, on a (1, 0) (pendule à droite) ; Il nous reste maintenant à générer la méthode .move() qui meut le pendule. Pour cela vous pouvez vous inspirez de la
— quand θ = −π/2 = −90 deg, on a (−1, 0) (pendule à gauche) ; rubrique Un canvas animé dans une classe du chapitre 20 Fenêtres graphiques et Tkinter.
— quand θ = ±π = ±180 deg, on a (0, 1) (pendule en haut). Cette méthode va réaliser un pas de simulation de t à t + δt. Il faudra ainsi réaliser dans l’ordre :
La figure 22.3 montre graphiquement les valeurs de θ . — Calculer la nouvelle valeur de θ (self.theta) au pas t + δt comme nous l’avons fait précédemment avec la méthode
Si vous n’avez pas trouvé, voici la solution : semi-implicite d’Euler.
1 self . x = np . sin ( self . theta ) * self . L — Convertir la nouvelle valeur de θ (self.theta) en coordonnées cartésiennes dans le repère du pendule (self.x et
2 self . y = - np . cos ( self . theta ) * self . L self.y).
— Convertir ces coordonnées cartésiennes dans le repère du Canvas (self.x_c et self.y_c).
— Mettre à jour le dessin de la baballe et de la tige avec la méthode self.canv.coords().
Conversion des coordonnées (x, y) en (xc , yc ) Il nous faut maintenant convertir les coordonnées naturelles mathématiques
— Incrémenter le pas de temps.
du pendule (x, y) en coordonnées dans le canvas (xc , yc ). Plusieurs choses sont importantes pour cela :
— Si le drapeau self.is_moving est supérieur à 0, la méthode self.move() est rappelée après 20 millisecondes
— le centre du repère mathématique (0, 0) a la coordonnée (200, 200) dans le canvas ;
(Conseil : la méthode .after() est votre amie).
— il faut choisir un facteur de conversion : par exemple, si on choisit L = 1 m, on peut proposer le facteur 1 m → 100
pixels ;
— l’axe des ordonnées dans le canvas est inversé par rapport au repère mathématique. Ressources complémentaires
Si vous en êtes arrivé là, bravo vous pouvez maintenant admirer votre superbe pendule en mouvement :-) !
Conseil Voici quelques indications si vous voulez aller un peu plus loin.
Dans votre classe, cela peut être une bonne idée d’écrire une méthode qui réalise cette conversion. Celle-ci pourrait Si vous souhaitez mettre une réglette pour modifier la position de départ du pendule, vous pouvez utiliser la classe
s’appeler par exemple map_realcoor2canvas(). tk.Scale(). Si vous souhaitez afficher la valeur de θ qui se met à jour au fur et à mesure, il faudra instancier un objet
avec la classe tk.StringVar(). Cet objet devra être passé à l’argument textvariable lors de la création de ce Label avec
tk.Label(). Ensuite, vous pourrez mettre à jour le texte du Label avec la méthode self.instance_StringVar.set().
Si vous n’avez pas trouvé, voici la solution : Pour le fun, si vous souhaitez laisser une « trace » du passage du pendule avec des points colorés, vous pouvez utiliser tout
1 self . conv_factor = 100 simplement la méthode self.canv.create_line() et créer une ligne d’un pixel de hauteur et de largeur pour dessiner un
2 self . x_c = self . x * self . conv_factor + 200
3 self . y_c = - self . y * self . conv_factor + 200 point. Pour améliorer l’esthétique, vous pouvez faire en sorte que ces points changent de couleur aléatoirement à chaque arrêt
/ redémarrage du pendule.
Si vous souhaitez aller plus loin sur les différentes méthodes numériques de résolution d’équation différentielle associées
Gestion des boutons au pendule, nous vous conseillons le site de James Sethna 20 de l’Université de Cornell.
Il reste maintenant à gérer les boutons permettant de démarrer / stopper le pendule. Pour cela il faudra créer 3 méthodes
dans notre classe :
— la méthode .start() : met en mouvement le pendule ; si le pendule n’a jamais été en mouvement, il part de son point 22.3 Scripts de correction
de départ ; si le pendule avait déjà été en mouvement, celui-ci repart d’où on l’avait arrêté (avec la vitesse qu’il avait à
Voici les scripts corrigés pour les différents mini-projets.
ce moment là) ;
— la méthode .stop() : arrête le mouvement du pendule ;
— la méthode .move() : gère le mouvement du pendule (génère les coordonnées du pendule au pas suivant). Remarque
Le bouton « Démarrer » appellera la méthode .start(), le bouton « Arrêter » appellera la méthode .stop() et le bouton — Prenez le temps de chercher par vous-même avant de télécharger les scripts de correction.
« Quitter » quittera l’application. Pour lier une action au clic d’un bouton, on se souvient qu’il faut donner à l’argument par 19. https://inforef.be/swi/python.htm
mot-clé command une callback (c’est-à-dire le nom d’une fonction ou méthode sans les parenthèses) : 20. http://pages.physics.cornell.edu/~sethna/StatMech/ComputerExercises/Pendulum/Pendulum.html
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 263 264 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
22.3. Scripts de correction Chapitre 22. Mini-projets
A.1 FASTA
Le format FASTA est utilisé pour stocker une ou plusieurs séquences, d’ADN, d’ARN ou de protéines.
Ces séquences sont classiquement représentées sous la forme :
1 >en - t ê te
2 s é quence avec un nombre maximum de caract è res par ligne
3 s é quence avec un nombre maximum de caract è res par ligne
4 s é quence avec un nombre maximum de caract è res par ligne
5 s é quence avec un nombre maximum de caract è res par ligne
6 s é quence avec un nombre max
La première ligne débute par le caractère > et contient une description de la séquence. On appelle souvent cette ligne «
ligne de description » ou « ligne de commentaire ».
Les lignes suivantes contiennent la séquence à proprement dite, mais avec un nombre maximum fixe de caractères par
ligne. Ce nombre maximum est généralement fixé à 60, 70 ou 80 caractères. Une séquence de plusieurs centaines de bases ou
de résidus est donc répartie sur plusieurs lignes.
Un fichier est dit multifasta lorsqu’il contient plusieurs séquences au format FASTA, les unes à la suite des autres.
Les fichiers contenant une ou plusieurs séquences au format FASTA portent la plupart du temps l’extension .fasta mais
on trouve également .seq, .fas, .fna ou .faa.
A.1.1 Exemples
La séquence protéique au format FASTA de la sous-unité β de l’hémoglobine humaine 1 , extraite de la base de données
UniProt, est :
1 > sp | P68871 | HBB_HUMAN Hemoglobin subunit beta OS = Homo sapiens OX =9606 GN = HBB PE =1 SV =2
2 MVHLTPEEKSAVTALWGKVNVDEVGGEALGRLLVVYPWTQRFFESFGDLSTPDAVMGNPK
3 VKAHGKKVLGAFSDGLAHLDNLKGTFATLSELHCDKLHVDPENFRLLGNVLVCVLAHHFG
4 KEFTPPVQAAYQKVVAGVANALAHKYH
La première ligne contient la description de la séquence (Hemoglobin subunit beta), le type de base de données (ici sp
qui signifie Swiss-Prot), son identifiant (P68871) et son nom (HBB_HUMAN) dans cette base de données, ainsi que d’autres
informations (S=Homo sapiens OX=9606 GN=HBB PE=1 SV=2).
Les lignes suivantes contiennent la séquence sur des lignes ne dépassant pas, ici, 60 caractères. La séquence de la sous-
unité β de l’hémoglobine humaine est composée de 147 acides aminés, soit deux lignes de 60 caractères et une troisième de
27 caractères.
Définition
21. https://python.sdv.univ-paris-diderot.fr/data-files/words_in_proteome.py UniProt 2 est une base de données de séquences de protéines. Ces séquences proviennent elles-mêmes de deux autres
22. https://python.sdv.univ-paris-diderot.fr/data-files/genbank2fasta_sans_regex.py bases de données : Swiss-Prot (où les séquences sont annotées manuellement) et TrEMBL (où les séquences sont annotées
23. https://python.sdv.univ-paris-diderot.fr/data-files/genbank2fasta_avec_regex.py
24. https://python.sdv.univ-paris-diderot.fr/data-files/tk_pendule_simple.py 1. https://www.uniprot.org/uniprot/P68871
25. https://python.sdv.univ-paris-diderot.fr/data-files/tk_pendule.py 2. https://www.uniprot.org/
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 265 266
A.1. FASTA Annexe A. Quelques formats de données rencontrés en biologie Annexe A. Quelques formats de données rencontrés en biologie A.2. GenBank
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 267 268 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
A.3. PDB Annexe A. Quelques formats de données rencontrés en biologie Annexe A. Quelques formats de données rencontrés en biologie A.3. PDB
Ligne 9 (gene 1..800) : la délimitation du gène. Ici de la base 1 à la base 800. Par ailleurs, la notation A.3.1 En-tête
<x..y indique que la séquence est partielle sur l’extrémité 5’. Réciproquement, x..y> indique que la séquence est partielle
sur l’extrémité 3’. Enfin, pour les séquences d’ADN, la notation complement(x..y) indique que le gène se trouve de la base Pour la trypsine bovine, l’en-tête compte 510 lignes. En voici quelques unes :
x à la base y, mais sur le brin complémentaire. 1 HEADER HYDROLASE ( SERINE PROTEINASE ) 26 - OCT -81 2 PTN
2 TITLE ON THE DISORDERED ACTIVATION DOMAIN IN TRYPSINOGEN .
Ligne 10 (/gene="TRY1") : le nom du gène. 3 TITLE 2 CHEMICAL LABELLING AND LOW - TEMPERATURE C RY STA LL OG RA PHY
Ligne 11 (CDS 7..750) : la délimitation de la séquence codante. 4 COMPND MOL_ID : 1;
5 COMPND 2 MOLECULE : TRYPSIN ;
Ligne 14 (/product="trypsinogen") : le nom de la protéine produite. 6 COMPND 3 CHAIN : A ;
Ligne 17 à 20 (/translation="MNPLLIL...) : la séquence protéique issue de la traduction de la séquence codante. 7 [...]
8 SOURCE 2 O R G A N I S M _ S C I E N T I F I C : BOS TAURUS ;
Ligne 22 (sig_peptide 7..51) : la délimitation du peptide signal. 9 [...]
EXPDTA X - RAY DIFFRACTION
A.2.3 La séquence 10
11 [...]
12 REMARK 2 RESOLUTION . 1.55 ANGSTROMS .
1 [...] 13 [...]
2 ORIGIN 14 DBREF 2 PTN A 16 245 UNP P00760 TRY1_BOVIN 21 243
3 1 accaccatga atccactcct gatccttacc tttgtggcag ctgctcttgc tgcccccttt 15 SEQRES 1 A 223 ILE VAL GLY GLY TYR THR CYS GLY ALA ASN THR VAL PRO
4 61 gatgatgatg acaagatcgt tgggggctac aactgtgagg agaattctgt cccctaccag 16 SEQRES 2 A 223 TYR GLN VAL SER LEU ASN SER GLY TYR HIS PHE CYS GLY
5 121 gtgtccctga attctggcta ccacttctgt ggtggctccc tcatcaacga acagtgggtg 17 SEQRES 3 A 223 GLY SER LEU ILE ASN SER GLN TRP VAL VAL SER ALA ALA
6 181 gtatcagcag gccactgcta caagtcccgc atccaggtga gactgggaga gcacaacatc 18 SEQRES 4 A 223 HIS CYS TYR LYS SER GLY ILE GLN VAL ARG LEU GLY GLU
7 241 gaagtcctgg aggggaatga gcagttcatc aatgcagcca agatcatccg ccacccccaa 19 [...]
8 301 tacgacagga agactctgaa caatgacatc atgttaatca agctctcctc acgtgcagta 20 HELIX 1 H1 SER A 164 ILE A 176 1 SNGL ALPHA TURN , REST IRREG . 13
9 361 atcaacgccc gcgtgtccac catctctctg cccaccgccc ctccagccac tggcacgaag 21 HELIX 2 H2 LYS A 230 VAL A 235 5 CONTIGUOUS WITH H3 6
10 421 tgcctcatct ctggctgggg caacactgcg agctctggcg ccgactaccc agacgagctg 22 HELIX 3 H3 SER A 236 ASN A 245 1 CONTIGUOUS WITH H2 10
11 481 cagtgcctgg atgctcctgt gctgagccag gctaagtgtg aagcctccta ccctggaaag 23 SHEET 1 A 7 TYR A 20 THR A 21 0
12 541 attaccagca acatgttctg tgtgggcttc cttgagggag gcaaggattc atgtcagggt 24 SHEET 2 A 7 LYS A 156 PRO A 161 -1 N CYS A 157 O TYR A 20
13 601 gattctggtg gccctgtggt ctgcaatgga cagctccaag gagttgtctc ctggggtgat 25 [...]
14 661 ggctgtgccc agaagaacaa gcctggagtc tacaccaagg tctacaacta cgtgaaatgg 26 SSBOND 1 CYS A 22 CYS A 157 1555 1555 2.04
15 721 attaagaaca ccatagctgc caatagctaa agcccccagt atctcttcag tctctatacc 27 SSBOND 2 CYS A 42 CYS A 58 1555 1555 2.02
16 781 aataaagtga ccctgttctc 28 [...]
17 //
Ligne 1. Cette ligne HEADER contient le nom de la protéine (HYDROLASE (SERINE PROTEINASE)), la date de dépôt de
La séquence est contenue entre les balises ORIGIN (ligne 2) et // (ligne 17).
cette structure dans la banque de données (26 octobre 1981) et l’identifiant de la structure dans la PDB, on parle souvent de «
Chaque ligne est composée d’une série d’espaces, puis du numéro du premier nucléotide de la ligne, puis d’au plus 6 blocs
code PDB » (2PTN).
de 10 nucléotides. Chaque bloc est précédé d’un espace.
Par exemple, ligne 10, le premier nucléotide de la ligne (t) est le numéro 421 dans la séquence. Ligne 2. TITLE correspond au titre de l’article scientifique dans lequel a été publié cette structure.
Lignes 4-6. COMPND indique que la trypsine est composée d’une seule chaîne peptidique, appelée ici A.
A.2.4 Manipulation avec Python
Ligne 8. SOURCE indique le nom scientifique de l’organisme dont provient cette protéine (ici, le bœuf).
À partir de l’exemple précédent, voici comment lire un fichier GenBank avec Python et le module Biopython : Ligne 10. EXPDTA précise la technique expérimentale employée pour déterminer cette structure. Ici, la cristallographie
1 from Bio import SeqIO aux rayons X. Mais on peut également trouver SOLUTION NMR pour de la résonance magnétique nucléaire en solution,
2 with open (" M22612 . gbk " , " r ") as gbk_file : ELECTRON MICROSCOPY pour de la microscopie électronique. . .
record = SeqIO . read ( gbk_file , " genbank ")
Ligne 12. REMARK 2 précise, dans le cas d’une détermination par cristallographie aux rayons X, la résolution obtenue,
3
4 print ( record . id )
5 print ( record . description ) ici 1,55 Angströms.
6 print ( record . seq [:60]) Ligne 14. DBREF indique les liens éventuels vers d’autres banques de données. Ici, l’identifiant correspondant à cette
Pour la séquence lue dans le fichier GenBank, on affiche son identifiant, sa description et les 60 premiers résidus : protéine dans UniProt (UNP) est P00760 11 .
1 M22612 .1
Ligne 15-18. SEQRES donnent à la séquence de la protéine. Les résidus sont représentés par leur code à 3 lettres.
2 Human pancreatic trypsin 1 ( TRY1 ) mRNA , complete cds . Lignes 20-22 et 23-24. HELIX et SHEET correspondent aux structures secondaires hélices α et brin β de cette protéine.
3 ACCACCATGAATCCACTCCTGATCCTTACCTTTGTGGCAGCTGCTCTTGCTGCCCCCTTT
Ici, H1 SER A 164 ILE A 176 indique qu’il y a une première hélice α (H1) comprise entre les résidus Ser164 et Ile176 de la
Il est également possible de lire un fichier GenBank sans le module Biopython. Une activité dédiée est proposée dans le chaîne A.
chapitre 22 Mini-projets. Lignes 26-27. SSBOND indique les bonds disulfures. Ici, entre les résidus Cys22 et Cys157 et entre les résidus Cys42 et
Cys58.
A.3 PDB
A.3.2 Coordonnées
La Protein Data Bank 8 (PDB) est une banque de données qui contient les structures de biomacromolécules (protéines,
Avec la même protéine, la partie coordonnées représente plus de 1700 lignes. En voici quelques unes correspondantes au
ADN, ARN, virus. . . ). Historiquement, le format de fichier qui y est associé est le PDB, dont une documentation détaillée est
résidu leucine 99 :
disponible sur le site éponyme 9 . Les principales extensions de fichier pour ce format de données sont .ent et surtout .pdb.
1 [...]
Un fichier PDB est constitué de deux parties principales : l’en-tête et les coordonnées. L’en-tête est lisible et utilisable 2 ATOM 601 N LEU A 99 10.007 19.687 17.536 1.00 12.25 N
par un être humain (et aussi par une machine). À l’inverse les coordonnées sont surtout utilisables par un programme pour 3 ATOM 602 CA LEU A 99 9.599 18.429 18.188 1.00 12.25 C
4 ATOM 603 C LEU A 99 10.565 17.281 17.914 1.00 12.25 C
calculer certaines propriétés de la structure ou simplement la représenter sur l’écran d’un ordinateur. Bien sûr, un utilisateur 5 ATOM 604 O LEU A 99 10.256 16.101 18.215 1.00 12.25 O
expérimenté peut parfaitement jeter un œil à cette seconde partie. 6 ATOM 605 CB LEU A 99 8.149 18.040 17.853 1.00 12.25 C
7 ATOM 606 CG LEU A 99 7.125 19.029 18.438 1.00 18.18 C
Examinons ces deux parties avec la trypsine bovine 10 . 8 ATOM 607 CD1 LEU A 99 5.695 18.554 18.168 1.00 18.18 C
9 ATOM 608 CD2 LEU A 99 7.323 19.236 19.952 1.00 18.18 C
8. https://www.rcsb.org/ 10 [...]
9. http://www.wwpdb.org/documentation/file-format-content/format33/v3.3.html
10. https://www.rcsb.org/structure/2PTN 11. https://www.uniprot.org/uniprot/P00760
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 269 270 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
A.3. PDB Annexe A. Quelques formats de données rencontrés en biologie Annexe A. Quelques formats de données rencontrés en biologie A.3. PDB
Vous remarquez que le numéro du premier résidu est 16 et non pas 1. Cela s’explique par la technique expérimentale
utilisée qui n’a pas permis de déterminer la structure des 15 premiers résidus.
La structure de la trypsine bovine n’est constituée que d’une seule chaîne peptidique (notée A). Lorsqu’une structure est
composée de plusieurs chaînes, comme dans le cas de la structure du récepteur GABAB 1 et 2 chez la drosophile (code PDB
5X9X 13 ) :
1 [...]
2 ATOM 762 HB1 ALA A 44 37.162 -2.955 2.220 1.00 0.00 H
3 ATOM 763 HB2 ALA A 44 38.306 -2.353 3.417 1.00 0.00 H
4 ATOM 764 HB3 ALA A 44 38.243 -1.621 1.814 1.00 0.00 H
5 TER 765 ALA A 44
6 ATOM 766 N GLY B 95 -18.564 3.009 13.772 1.00 0.00 N
7 ATOM 767 CA GLY B 95 -19.166 3.646 12.621 1.00 0.00 C
8 ATOM 768 C GLY B 95 -20.207 2.755 11.976 1.00 0.00 C
9 [...]
La première chaîne est notée A et la seconde B. La séparation entre les deux est marquée par la ligne TER 765
ALA A 44.
Dans un fichier PDB, chaque structure porte un nom de chaîne différent.
Enfin, lorsque la structure est déterminée par RMN, il est possible que plusieurs structures soient présentes dans le même
F IGURE A.1 – Structure tridimensionnelle d’un résidu leucine. Les noms des atomes sont indiqués en noir. fichier PDB. Toutes ces structures, ou « modèles », sont des solutions possibles du jeu de contraintes mesurées expérimenta-
lement en RMN. Voici un exemple, toujours pour la structure du récepteur GABAB 1 et 2 chez la drosophile :
1 [...]
Chaque ligne correspond à un atome et débute par ATOM ou HETATM. ATOM désigne un atome de la structure de la biomo- 2 MODEL 1
ATOM 1 N MET A 1 -27.283 -9.772 5.388 1.00 0.00 N
lécule. HETATM est utilisé pour les atomes qui ne sont pas une biomolécule, comme les ions ou les molécules d’eau. 3
4 ATOM 2 CA MET A 1 -28.233 -8.680 5.682 1.00 0.00 C
Toutes les lignes de coordonnées ont sensiblement le même format. Par exemple, pour la première ligne : 5 [...]
ATOM 1499 HG2 GLU B 139 36.113 -5.242 2.536 1.00 0.00 H
— ATOM (ou HETATM). 6
7 ATOM 1500 HG3 GLU B 139 37.475 -4.132 2.428 1.00 0.00 H
— 601 : le numéro de l’atome. 8 TER 1501 GLU B 139
ENDMDL
— N : le nom de l’atome. Ici, un atome d’azote du squelette peptidique. La structure complète du résidu leucine est
9
10 MODEL 2
représentée figure A.1. 11 ATOM 1 N MET A 1 -29.736 -10.759 4.394 1.00 0.00 N
12 ATOM 2 CA MET A 1 -28.372 -10.225 4.603 1.00 0.00 C
— LEU : le résidu dont fait partie l’atome. Ici une leucine. 13 [...]
— A : le nom de la chaîne peptidique. 14 ATOM 1499 HG2 GLU B 139 36.113 -5.242 2.536 1.00 0.00 H
15 ATOM 1500 HG3 GLU B 139 37.475 -4.132 2.428 1.00 0.00 H
— 99 : le numéro du résidu dans la protéine. 16 TER 1501 GLU B 139
— 10.007 : la coordonnées x de l’atome. 17 ENDMDL
18 MODEL 2
— 19.687 : la coordonnées y de l’atome. 19 ATOM 1 N MET A 1 -29.736 -10.759 4.394 1.00 0.00 N
ATOM 2 CA MET A 1 -28.372 -10.225 4.603 1.00 0.00 C
— 17.536 : la coordonnées z de l’atome.
20
21 [...]
— 1.00 : le facteur d’occupation, c’est-à-dire la probabilité de trouver l’atome à cette position dans l’espace en moyenne.
Cette probabilité est inférieure à 1 lorsque, expérimentalement, on n’a pas pu déterminer avec une totale certitude la Chaque structure est encadrée par les lignes
position de l’atome. Par exemple dans le cas d’un atome très mobile dans une structure, qui est déterminé comme étant 1 MODEL n
à deux positions possibles, chaque position aura alors la probabilité 0,50.
et
— 12.25 : le facteur de température qui est proportionnel à la mobilité de l’atome dans l’espace. Les atomes situés en
périphérie d’une structure sont souvent plus mobiles que ceux situés au coeur de la structure. 1 ENDMDL
— N : l’élément chimique de l’atome. Ici, l’azote. où n est le numéro du modèle. Pour la structure du récepteur GABAB 1 et 2, il y a 20 modèles de décrits dans le fichier
Une documentation plus complète des différents champs qui constituent une ligne de coordonnées atomiques se trouve sur PDB.
le site de la PDB 12 .
Les résidus sont ensuite décrits les uns après les autres, atome par atome. Voici par exemple les premiers résidus de la
trypsine bovine : A.3.3 Manipulation avec Python
1 [...] Le module Biopython peut également lire un fichier PDB.
2 ATOM 1 N ILE A 16 -8.155 9.648 20.365 1.00 10.68 N
3 ATOM 2 CA ILE A 16 -8.150 8.766 19.179 1.00 10.68 C Chargement de la structure de la trypsine bovine :
4 ATOM 3 C ILE A 16 -9.405 9.018 18.348 1.00 10.68 C
5 ATOM 4 O ILE A 16 -10.533 8.888 18.870 1.00 10.68 O 1 from Bio . PDB import PDBParser
6 ATOM 5 CB ILE A 16 -8.091 7.261 19.602 1.00 10.68 C 2 parser = PDBParser ()
7 ATOM 6 CG1 ILE A 16 -6.898 6.882 20.508 1.00 7.42 C 3 prot_id = "2 PTN "
8 ATOM 7 CG2 ILE A 16 -8.178 6.281 18.408 1.00 7.42 C 4 prot_file = "2 PTN . pdb "
9 ATOM 8 CD1 ILE A 16 -5.555 6.893 19.773 1.00 7.42 C 5 structure = parser . get_structure ( prot_id , prot_file )
10 ATOM 9 N VAL A 17 -9.224 9.305 17.090 1.00 9.63 N
11 ATOM 10 CA VAL A 17 -10.351 9.448 16.157 1.00 9.63 C
12 ATOM 11 C VAL A 17 -10.500 8.184 15.315 1.00 9.63 C
13 ATOM 12 O VAL A 17 -9.496 7.688 14.748 1.00 9.63 O Remarque
14 ATOM 13 CB VAL A 17 -10.123 10.665 15.222 1.00 9.63 C
15 ATOM 14 CG1 VAL A 17 -11.319 10.915 14.278 1.00 11.95 C Les fichiers PDB sont parfois (très) mal formatés. Si Biopython ne parvient pas à lire un tel fichier, remplacez alors la 2e
16 ATOM 15 CG2 VAL A 17 -9.737 11.970 15.970 1.00 11.95 C ligne par parser = PDBParser(PERMISSIVE=1). Soyez néanmoins très prudent quant aux résultats obtenus.
17 [...]
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 271 272 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
A.3. PDB Annexe A. Quelques formats de données rencontrés en biologie Annexe A. Quelques formats de données rencontrés en biologie A.3. PDB
ce qui produit :
1 hydrolase ( serine proteinase )
2 x - ray diffraction
ce qui produit :
1 ILE [ -8.15499973 9.64799976 20.36499977]
2 VAL [ -10.35099983 9.44799995 16.15699959]
L’objet res1["N"].coord est un array de NumPy (voir le chapitre 17 Quelques modules d’intérêt en bioinformatique).
On peut alors obtenir simplement les coordonnées x, y et z d’un atome :
1 print ( res1 [" N "]. coord [0] , res1 [" N "]. coord [1] , res1 [" N "]. coord [2])
ce qui produit :
1 -8.155 9.648 20.365
Remarque
Biopython utilise la hiérarchie suivante :
structure > model > chain > residue > atom
même lorsque la structure ne contient qu’un seul modèle. C’est d’ailleurs le cas ici, puisque la structure a été obtenue par
cristallographie aux rayons X.
Enfin, pour afficher les coordonnées des carbones α (notés CA) des 10 premiers résidus (à partir du résidu 16 car c’est le
premier résidu dont on connaît la structure) :
1 res_start = 16
2 model = structure [0]
3 chain = model [" A "]
4 for i in range (10):
5 idx = res_start + i
6 print ( chain [ idx ]. resname , idx , chain [ idx ][" CA "]. coord )
Il est aussi très intéressant (et formateur) d’écrire son propre parser de fichier PDB, c’est-à-dire un programme qui lit un
fichier PDB (sans le module Biopython). Dans ce cas, la figure A.2 vous aidera à déterminer comment extraire les différentes
informations d’une ligne de coordonnées ATOM ou HETATM.
Exemple : pour extraire le nom du résidu, il faut isoler le contenu des colonnes 18 à 20 du fichier PDB, ce qui correspond
aux index de 17 à 19 pour une chaîne de caractères en Python, soit la tranche de chaîne de caractères [17:20] car la première
borne est incluse et la seconde exclue.
Pour lire le fichier PDB de la trypsine bovine (2PTN.pdb) et extraire (encore) les coordonnées des carbones α des 10
premiers résidus, nous pouvons utiliser le code suivant :
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 273 274 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
A.4. Format XML, CSV et TSV Annexe A. Quelques formats de données rencontrés en biologie Annexe A. Quelques formats de données rencontrés en biologie A.4. Format XML, CSV et TSV
1 with open ("2 PTN . pdb " , " r ") as pdb_file : 1 <? xml version = '1.0 ' encoding = ' UTF -8 '? >
2 res_count = 0 2 < uniprot xmlns =" http :// uniprot . org / uniprot " xmlns : xsi =[...] >
3 for line in pdb_file : 3 < entry dataset =" Swiss - Prot " created ="1988 -04 -01" modified ="2018 -09 -12" [...] >
4 if line . startswith (" ATOM "): 4 < accession > P07477 </ accession >
5 atom_name = line [12:16]. strip () 5 < accession > A1A509 </ accession >
6 res_name = line [17:20]. strip () 6 < accession > A6NJ71 </ accession >
7 res_num = int ( line [22:26]) 7 [...]
8 if atom_name == " CA ": 8 < gene >
9 res_count += 1 9 < name type =" primary " > PRSS1 </ name >
10 x = float ( line [30:38]) 10 < name type =" synonym " > TRP1 </ name >
11 y = float ( line [38:46]) 11 < name type =" synonym " > TRY1 </ name >
12 z = float ( line [46:54]) 12 < name type =" synonym " > TRYP1 </ name >
13 print ( res_name , res_num , x , y , z ) </ gene >
if res_count >= 10:
13
14
15 break 14 [...]
15 < sequence length ="247" mass ="26558" checksum =" D D 4 9A 48 7 B 8 0 62 8 1 3 " [...] >
ce qui donne : 16 MNPLLILTFVAAALAAPFDDDDKIVGGYNCEENSVPYQVSLNSGYHFCGGSLINEQWVVS
17 AGHCYKSRIQVRLGEHNIEVLEGNEQFINAAKIIRHPQYDRKTLNNDIMLIKLSSRAVIN
1 ILE 16 -8.15 8.766 19.179 18 ARVSTISLPTAPPATGTKCLISGWGNTASSGADYPDELQCLDAPVLSQAKCEASYPGKIT
2 VAL 17 -10.351 9.448 16.157 19 SNMFCVGFLEGGKDSCQGDSGGPVVCNGQLQGVVSWGDGCAQKNKPGVYTKVYNYVKWIK
3 GLY 18 -12.021 6.63 14.259 20 NTIAANS
4 GLY 19 -10.902 3.899 16.684 21 </ sequence >
5 TYR 20 -12.651 1.442 19.016 22 </ entry >
6 THR 21 -13.018 0.938 22.76 23 [...]
CYS 22 -10.02 -1.163 23.76
</ uniprot >
7
8 GLY 23 -11.683 -2.865 26.714 24
Le format XML est un format de fichier qui permet de stocker quasiment n’importe quel type d’information de façon 9 root = etree . fromstring ( xml_content . encode (" utf -8"))
10
structurée et hiérarchisée. L’acronyme XML signifie Extensible Markup Language qui pourrait se traduire en français par « 11 for gene in root . xpath ("/ uniprot / entry / gene / name "):
Langage de balisage extensible 14 ». Les balises dont il est question servent à délimiter du contenu : 12 print ( f " gene : { gene . text } ({ gene . get ( ' type ')})")
<balise>contenu</balise> 13
14 sequence = root . xpath ("/ uniprot / entry / sequence ")[0]
La balise <balise> est une balise ouvrante. La balise </balise> est une balise fermante. Notez le caractère / qui marque 15 print ( f " sequence : { sequence . text . strip ()}")
la différence entre une balise ouvrante et une balise fermante. 16 print ( f " length : { sequence . get ( ' length ')}")
Il existe également des balises vides, qui sont à la fois ouvrantes et fermantes : Ligne 1. On utilise le sous-module etree du module lxml pour lire le fichier XML.
<balise /> Ligne 2. On utilise le module d’expressions régulières re pour supprimer tous les attributs de la balise uniprot (ligne 7).
Une balise peut avoir certaines propriétés, appelées attributs, qui sont définies, dans la balise ouvrante. Par exemple : Nous ne rentrerons pas dans les détails, mais ces attributs rendent plus complexe la lecture du fichier XML.
<balise propriété1=valeur1 propriété2=valeur2>contenu</balise> Ligne 9. La variable root contient le fichier XML prêt à être manipulé.
Un attribut est un couple nom et valeur (par exemple propriété1 est un nom et valeur1 est la valeur associée).
Ligne 11. On recherche les noms des gènes (balises <name></name>) associés à la trypsine. Pour cela, on utilise la
Enfin, les balises peuvent être imbriquées les unes dans les autres :
méthode .xpath() avec comme argument l’enchaînement des différentes balises qui conduisent aux noms des gènes.
< protein >
1
2 < element > é l é ment 1 </ element > Ligne 12. Pour chaque nom de gène, on va afficher son contenu (gene.text) et la valeur associée à l’attribut type avec
3 < element > é l é ment 2 </ element > la méthode .get("type").
4 < element > é l é ment 3 </ element > Ligne 11. On stocke dans la variable sequence la balise associée à la séquence de la protéine. Comme root.xpath("/uniprot/entry/
</ protein >
renvoie un itérateur et qu’il n’y a qu’une seule balise séquence, on prend ici le seul et unique élément root.xpath("/uniprot/entry/sequ
5
Dans cet exemple, nous avons trois balises element qui sont contenues dans une balise protein. Ligne 15. On affiche le contenu de la séquence sequence.text, nettoyé d’éventuels retours chariots ou espaces sequence.text.strip
Voici un autre exemple avec l’enzyme trypsine 15 humaine (code P07477 16 ) telle qu’on peut la trouver décrite dans la base Ligne 16. On affiche la taille de la séquence en récupérant la valeur de l’attribut length (toujours de la balise <sequence></sequence>)
de données UniProt : Le résultat obtenu est le suivant :
14. https://fr.wikipedia.org/wiki/Extensible_Markup_Language 1 gene : PRSS1 ( primary )
15. https://www.uniprot.org/uniprot/P07477 2 gene : TRP1 ( synonym )
16. https://www.uniprot.org/uniprot/P07477.xml 3 gene : TRY1 ( synonym )
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 275 276 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
A.4. Format XML, CSV et TSV Annexe A. Quelques formats de données rencontrés en biologie Annexe A. Quelques formats de données rencontrés en biologie A.4. Format XML, CSV et TSV
4 gene : TRYP1 ( synonym ) Le caractère tabulation est un caractère invisible « élastique », c’est-à-dire qu’il a une largeur variable suivant l’éditeur de
5 sequence : M N P L L I L T F V A A A L A A P F D D D D K I V G G Y N C E E N S V P Y Q V S L N S G Y H F C G G S L I N E Q W V V S
6 AGHCYKSRIQVRLGEHNIEVLEGNEQFINAAKIIRHPQYDRKTLNNDIMLIKLSSRAVIN texte utilisé. Par exemple, dans la ligne d’en-tête, l’espace entre PDB ID et Source apparaît comme différent de l’espace entre
7 ARVSTISLPTAPPATGTKCLISGWGNTASSGADYPDELQCLDAPVLSQAKCEASYPGKIT Deposit Date et Length alors qu’il y a pourtant une seule tabulation à chaque fois.
8 SNMFCVGFLEGGKDSCQGDSGGPVVCNGQLQGVVSWGDGCAQKNKPGVYTKVYNYVKWIK
9 NTIAANS
10 length : 247
Lecture
A.4.2 CSV et TSV
En Python, le module csv de la bibliothèque standard est très pratique pour lire et écrire des fichiers au format CSV et
Définition des formats TSV. Nous vous conseillons de lire la documentation très complète sur ce module 19 .
L’acronyme CSV signifie « Comma-Separated values » qu’on peut traduire littéralement par « valeurs séparées par des Voici un exemple :
virgules ». De façon similaire, TSV signifie « Tabulation-Separated Values », soit des « valeurs séparées par des tabulations ». 1 import csv
2
Ces deux formats sont utiles pour stocker des données structurées sous forme de tableau, comme vous pourriez l’avoir 3 with open (" t r a n s f e rr i n _ r e p o r t . csv ") as f_in :
dans un tableur. 4 f_reader = csv . DictReader ( f_in )
5 for row in f_reader :
À titre d’exemple, le tableau ci-dessous liste les structures associées à la transferrine, protéine présente dans le plasma 6 print ( row [" PDB ID "] , row [" Deposit Date "] , row [" Length "])
sanguin et impliquée dans la régulation du fer. Ces données proviennent de la Protein Data Bank (PDB). Pour chaque protéine
Ligne 1. Chargement du module csv.
(PDB ID), est indiqué le nom de l’organisme associé (Source), la date à laquelle cette structure a été déposée dans la PDB
Ligne 3. Ouverture du fichier.
(Deposit Date), le nombre d’acides aminés de la protéine et sa masse moléculaire (MW).
Ligne 4. Utilisation du module csv pour lire le fichier CSV comme un dictionnaire (fonction DictReader()). La ligne
d’en-tête est utilisée automatiquement pour définir les clés du dictionnaire.
PDB ID Source Deposit Date Length MW Ligne 5. Parcours de toutes les lignes du fichiers CSV.
1A8E Homo sapiens 1998-03-24 329 36408.40 Ligne 6. Affichage des champs correspondants à PDB ID, Deposit Date, Length.
1A8F Homo sapiens 1998-03-25 329 36408.40 Le résultat obtenu est :
1AIV Gallus gallus 1997-04-28 686 75929.00 1 1 A8E 1998 -03 -24 329
2 1 A8F 1998 -03 -25 329
1AOV Anas platyrhynchos 1996-12-11 686 75731.80 3 1 AIV 1997 -04 -28 686
1B3E Homo sapiens 1998-12-09 330 36505.50 4 1 AOV 1996 -12 -11 686
5 1 B3E 1998 -12 -09 330
1D3K Homo sapiens 1999-09-29 329 36407.40 6 1 D3K 1999 -09 -29 329
1D4N Homo sapiens 1999-10-04 329 36399.40 7 [...]
1DOT Anas platyrhynchos 1995-08-03 686 75731.80 Il suffit de modifier légèrement le script précédent pour lire un fichier TSV :
[. . . ] [. . . ] [. . . ] [. . . ] [. . . ] 1 import csv
2
3 with open (" t r a n s f e r r i n _ P D B _ r e p o r t . tsv ") as f_in :
Voici maintenant l’équivalent en CSV 17 : 4 f_reader = csv . DictReader ( f_in , delimiter ="\ t ")
5 for row in f_reader :
1 PDB ID , Source , Deposit Date , Length , MW 6 print ( row [" PDB ID "] , row [" Deposit Date "] , row [" Length "])
2 1 A8E , Homo sapiens ,1998 -03 -24 ,329 ,36408.40
3 1 A8F , Homo sapiens ,1998 -03 -25 ,329 ,36408.40 Ligne 3. Modification du nom du fichier lu.
1 AIV , Gallus gallus ,1997 -04 -28 ,686 ,75929.00
Ligne 4. Utilisation de l’argument delimiter="\t" qui indique que les champs sont séparés par des tabulations.
4
5 1 AOV , Anas platyrhynchos ,1996 -12 -11 ,686 ,75731.80
6 1 B3E , Homo sapiens ,1998 -12 -09 ,330 ,36505.50 Le résultat obtenu est strictement identique au précédent.
7 1 D3K , Homo sapiens ,1999 -09 -29 ,329 ,36407.40
8 1 D4N , Homo sapiens ,1999 -10 -04 ,329 ,36399.40
9 1 DOT , Anas platyrhynchos ,1995 -08 -03 ,686 ,75731.80
10 [...] Écriture
Sur chaque ligne, les différentes valeurs sont séparées par une virgule. La première ligne contient le nom des colonnes et Voici un exemple d’écriture de fichier CSV :
est appelée ligne d’en-tête. 1 import csv
2
L’équivalent en TSV 18 est : 3 with open (" test . csv " , " w ") as f_out :
4 fields = [" Name " , " Quantity "]
1 PDB ID Source Deposit Date Length MW f_writer = csv . DictWriter ( f_out , fieldnames = fields )
2 1 A8E Homo sapiens 1998 -03 -24 329 36408.40 5
3 1 A8F Homo sapiens 1998 -03 -25 329 36408.40 6 f_writer . writeheader ()
4 1 AIV Gallus gallus 1997 -04 -28 686 75929.00 7 f_writer . writerow ({" Name ": " girafe " , " Quantity ":5})
5 1 AOV Anas platyrhynchos 1996 -12 -11 686 75731.80 8 f_writer . writerow ({" Name ": " tigre " , " Quantity ":3})
6 1 B3E Homo sapiens 1998 -12 -09 330 36505.50 9 f_writer . writerow ({" Name ": " singe " , " Quantity ":8})
7 1 D3K Homo sapiens 1999 -09 -29 329 36407.40
8 1 D4N Homo sapiens 1999 -10 -04 329 36399.40 Ligne 3. Ouverture du fichier test.csv en lecture.
9 1 DOT Anas platyrhynchos 1995 -08 -03 686 75731.80
10 [...] Ligne 4. Définition du nom des colonnes (Name et Quantity).
Ligne 5. Utilisation du module csv pour écrire un fichier CSV à partir d’un dictionnaire.
Sur chaque ligne, les différentes valeurs sont séparées par une tabulation. Ligne 6. Écriture des noms des colonnes.
Ligne 7-9. Écriture de trois lignes. Pour chaque ligne, un dictionnaire dont les clefs sont les noms des colonnes est fourni
Attention comme argument à la méthode .writerow().
Le contenu du fichier test.csv est alors :
17. https://python.sdv.univ-paris-diderot.fr/data-files/transferrin_report.csv
18. https://python.sdv.univ-paris-diderot.fr/data-files/transferrin_report.tsv 19. https://docs.python.org/fr/3.7/library/csv.html
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 277 278 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
A.4. Format XML, CSV et TSV Annexe A. Quelques formats de données rencontrés en biologie
1 Name , Quantity
2 girafe ,5
3 tigre ,3
4 singe ,8
De façon très similaire, l’écriture d’un fichier TSV est réalisée avec le code suivant :
1 import csv
2
3
4
with open (" test . tsv " , " w ") as f_out :
fields = [" Name " , " Quantity "]
Annexe B
5 f_writer = csv . DictWriter ( f_out , fieldnames = fields , delimiter ="\ t ")
6 f_writer . writeheader ()
7 f_writer . writerow ({" Name ": " girafe " , " Quantity ":5})
f_writer . writerow ({" Name ": " tigre " , " Quantity ":3})
8
9 f_writer . writerow ({" Name ": " singe " , " Quantity ":8}) Installation de Python
Ligne 3. Modification du nom du fichier en écriture.
Ligne 5. Utilisation de l’argument delimiter="\t" qui indique que les champs sont séparés par des tabulations.
Le contenu du fichier test.tsv est :
1 Name Quantity
2 girafe 5
3 tigre 3 Attention
4 singe 8 Miniconda a été mis à jour le 29 juillet 2019, la procédure d’installation décrite ci-dessous concerne cette version.
Vous êtes désormais capables de lire et écrire des fichiers aux formats CSV et TSV. Les codes que nous vous avons
proposés ne sont que des exemples. À vous de poursuivre l’exploration du module csv. Python est déjà présent sous Linux ou Mac OS X et s’installe très facilement sous Windows. Toutefois, nous décrivons
dans cet ouvrage l’utilisation de modules supplémentaires qui sont très utiles en bioinformatique (NumPy, scipy, matplotlib,
Remarque pandas, Biopython), mais également les notebooks Jupyter.
Le module pandas décrit dans le chapitre 17 Quelques modules d’intérêt en bioinformatique est tout à fait capable de lire On va donc utiliser un gestionnaire de paquets qui va installer ces modules supplémentaires. On souhaite également que
et écrire des fichiers CSV et TSV. Nous vous conseillons de l’utiliser si vous analysez des données avec ces types de fichiers. ce gestionnaire de paquets soit disponible pour Windows, Mac OS X et Linux. Fin 2018, il y a deux grandes alternatives :
1. Anaconda et Miniconda : Anaconda 1 est une distribution complète de Python qui contient un gestionnaire de paquets
très puissant nommé conda. Anaconda installe de très nombreux paquets et outils mais nécessite un espace disque de
plusieurs gigaoctets. Miniconda 2 est une version allégée d’Anaconda, donc plus rapide à installer et occupant peu
d’espace sur le disque dur. Le gestionnaire de paquet conda est aussi présent dans Miniconda.
2. Pip : pip 3 est le gestionnaire de paquets de Python et qui est systématiquement présent depuis la version 3.4.
signifie l’invite d’un shell quel qu’il soit (PowerShell sous Windows, bash sous Mac OS X et Linux).
1. https://www.anaconda.com/
2. https://conda.io/miniconda.html
3. https://pip.pypa.io/en/stable/
4. https://conda.io/miniconda.html
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 279 280
B.2. Installation de Python avec Miniconda Annexe B. Installation de Python Annexe B. Installation de Python B.2. Installation de Python avec Miniconda
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 281 282 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
B.2. Installation de Python avec Miniconda Annexe B. Installation de Python Annexe B. Installation de Python B.2. Installation de Python avec Miniconda
— L’installateur vous demande où installer Miniconda, nous vous recommandons de laisser le choix par défaut (ressem-
blant à C:\Users\votre_nom_utilisateur\Miniconda3). Cliquez sur Next, vous arriverez sur :
— Lisez la licence et (si vous êtes d’accord) cliquez sur I agree. Vous aurez ensuite :
— Gardez la case Register Anaconda as my default Python 3.7 cochée et ne cochez pas la case Add Anaconda to my
— Gardez le choix de l’installation seulement pour vous (case cochée à Just me (recommended)), puis cliquez sur Next. PATH environment variable. Cliquez ensuite sur Install, l’installation se lance et durera quelques minutes :
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 283 284 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
B.2. Installation de Python avec Miniconda Annexe B. Installation de Python Annexe B. Installation de Python B.2. Installation de Python avec Miniconda
Initialisation de conda
Il nous faut maintenant initialiser conda. Cette manipulation va permettre de le rendre visible dans n’importe quel shell
Powershell.
L’installateur a en principe ajouté une nouvelle section dans le Menu Démarrer nommée Anaconda3 (64-bit) :
Lorsque vous presserez la touche Entrée vous obtiendrez une sortie de ce style :
1 $ conda init
2 no change C :\ Users \ Pat \ Miniconda3 \ Scripts \ conda . exe
3 no change C :\ Users \ Pat \ Miniconda3 \ Scripts \ conda - env . exe
4 no change C :\ Users \ Pat \ Miniconda3 \ Scripts \ conda - script . py
5 no change C :\ Users \ Pat \ Miniconda3 \ Scripts \ conda - env - script . py
— Cliquez sur Next, vous arriverez sur la dernière fenêtre : 6 no change C :\ Users \ Pat \ Miniconda3 \ condabin \ conda . bat
7 no change C :\ Users \ Pat \ Miniconda3 \ Library \ bin \ conda . bat
8 no change C :\ Users \ Pat \ Miniconda3 \ condabin \ _ co n da_a ct iva te . bat
9 no change C :\ Users \ Pat \ Miniconda3 \ condabin \ rename_tmp . bat
10 no change C :\ Users \ Pat \ Miniconda3 \ condabin \ c o n d a _ a u t o _ a c t i v a t e . bat
11 no change C :\ Users \ Pat \ Miniconda3 \ condabin \ conda_hook . bat
12 no change C :\ Users \ Pat \ Miniconda3 \ Scripts \ activate . bat
13 no change C :\ Users \ Pat \ Miniconda3 \ condabin \ activate . bat
14 no change C :\ Users \ Pat \ Miniconda3 \ condabin \ deactivate . bat
15 modified C :\ Users \ Pat \ Miniconda3 \ Scripts \ activate
16 modified C :\ Users \ Pat \ Miniconda3 \ Scripts \ deactivate
17 modified C :\ Users \ Pat \ Miniconda3 \ etc \ profile . d \ conda . sh
18 modified C :\ Users \ Pat \ Miniconda3 \ etc \ fish \ conf . d \ conda . fish
19 no change C :\ Users \ Pat \ Miniconda3 \ shell \ condabin \ Conda . psm1
20 modified C :\ Users \ Pat \ Miniconda3 \ shell \ condabin \ conda - hook . ps1
21 modified C :\ Users \ Pat \ Miniconda3 \ Lib \ site - packages \ xontrib \ conda . xsh
22 modified C :\ Users \ Pat \ Miniconda3 \ etc \ profile . d \ conda . csh
23 modified C :\ Users \ Pat \ Documents \ W i n d o w s P o w e rS h e ll \ profile . ps1
24 modified H K E Y_ C U R R E N T _ U S E R \ Software \ Microsoft \ Command Processor \ AutoRun
25
26 == > For changes to take effect , close and re - open your current shell . <==
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 285 286 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
B.2. Installation de Python avec Miniconda Annexe B. Installation de Python Annexe B. Installation de Python B.2. Installation de Python avec Miniconda
Test de l’interpréteur Python 18 info Display information about current conda install .
19 init Initialize conda for shell interaction . [ Experimental ]
Nous sommes maintenant prêts à tester l’interpréteur Python. En premier lieu, il faut lancer un shell PowerShell. Pour 20 install Installs a list of packages into a specified conda
21 environment .
cela, cliquez sur le bouton Windows et tapez powershell. Vous devriez voir apparaitre le menu suivant : 22 list List linked packages in a conda environment .
23 package Low - level conda package utility . ( EXPERIMENTAL )
24 remove Remove a list of packages from a specified conda environment .
25 uninstall Alias for conda remove .
26 run Run an executable in a conda environment . [ Experimental ]
27 search Search for packages and display associated information . The
28 input is a MatchSpec , a query language for conda packages .
29 See examples below .
30 update Updates conda packages to the latest compatible version .
31 upgrade Alias for conda update .
32
33 optional arguments :
34 -h , -- help Show this help message and exit .
35 -V , -- version Show the conda version number and exit .
36
37 conda commands available from other packages :
38 env
39 ( base ) PS C :\ Users \ Pat >
Cliquez sur l’icône Windows PowerShell, cela va lancer un shell PowerShell avec un fond bleu (couleur que l’on peut Si c’est le cas, bravo, conda est bien installé et vous pouvez passez à la suite (rendez-vous à la rubrique Installation des
bien sûr modifier en cliquant sur la petite icône représentant un terminal dans la barre de titre). En principe, l’invite du shell modules supplémentaires) !
doit ressembler à (base) PS C:\Users\Pat>. La partie (base) indique que conda a bien été activé suite à l’initialisation
faite si dessus (plus exactement c’est son environnement de base qui est activé, mais ça ne nous importe pas pour l’instant). Désinstallation de Miniconda
Pour tester si Python est bien installé, il suffit alors de lancer l’interpréteur Python en tapant la commande python :
Si vous souhaitez désinstaller Miniconda, rien de plus simple. Dans un explorateur, dirigez-vous dans le répertoire où vous
avez installé Miniconda (dans notre exemple il s’agit de C:\Users\votre_nom_utilisateur\Miniconda3). Attention, si
votre Windows est installé en français, il se peut qu’il faille cliquer sur C:\ puis sur Utilisateurs plutôt que Users comme
montré ici :
Cela signifie que vous êtes bien dans l’interpréteur Python. À partir de là vous pouvez taper exit() puis appuyer sur la Cliquez ensuite sur le fichier Uninstall-Miniconda3.exe. Vous aurez alors l’écran suivant :
touche Entrée pour sortir de l’interpréteur Python.
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 287 288 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
B.2. Installation de Python avec Miniconda Annexe B. Installation de Python Annexe B. Installation de Python B.3. Utilisation de conda pour installer des modules complémentaires
Cliquez sur Next, puis à l’écran suivant cliquez sur Uninstall : Puis enfin sur Finish :
Cette étape sera commune pour les trois systèmes d’exploitation. À nouveau, lancez un shell (c’est-à-dire PowerShell sous
Windows ou un terminal pour Mac OS X ou Linux).
Dans le shell, tapez la ligne suivante puis appuyez sur la touche Entrée :
Une fois la désinstallation terminée, cliquez sur Next : 1 $ conda install numpy pandas matplotlib scipy biopython jupyterlab
Cette commande va lancer l’installation des modules externes NumPy, pandas, matplotlib, scipy, Biopython et Jupyter lab.
Ces modules vont être téléchargés depuis internet par conda, il faut bien sûr que votre connexion internent soit fonctionnelle.
Au début, conda va déterminer les versions des paquets à télécharger en fonction de la version de Python ainsi que d’autres
paramètres (cela prend une à deux minutes). Cela devrait donner la sortie suivante (copies d’écran prise sous Windows avec
le PowerShell) :
Une fois que les versions des paquets ont été déterminées, conda vous demande confirmation avant de démarrer le télé-
chargement :
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 289 290 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
B.3. Utilisation de conda pour installer des modules complémentaires Annexe B. Installation de Python Annexe B. Installation de Python B.3. Utilisation de conda pour installer des modules complémentaires
2 import scipy
3 import Bio
4 import matplotlib
5 import pandas
Si aucune erreur ne s’affiche et que vous récupérez la main dans l’interpréteur, bravo, ces modules sont bien installés.
Tapez y puis appuyez sur la touche Entrée pour confirmer. S’en suit alors le téléchargement et l’installation de tous les Quittez l’interpréteur Python en tapant la commande exit() puis en appuyant sur la touche Entrée.
paquets (cela prendra quelques minutes) : Vous êtes de nouveau dans le shell. Nous allons maintenant pouvoir tester Jupyter. Tapez dans le shell :
1 $ jupyter lab
Cette commande devrait ouvrir votre navigateur internet par défaut et lancer Jupyter :
Pour quitter Jupyter, allez dans le menu File puis sélectionnez Quit. Vous pourrez alors fermer l’onglet de Jupyter. Pendant
ces manipulations dans le navigateur, de nombreuses lignes ont été affichées dans l’interpréteur :
1 ( base ) PS C :\ Users \ Pat > jupyter lab
Une fois que tout cela est terminé, vous récupérez la main dans le shell : 2 [ I 18:26:05.544 LabApp ] JupyterLab extension loaded from C :\ Users \ Pat \ Miniconda3 \ lib \ site - packages \ jupyterla
3 [ I 18:26:05.544 LabApp ] JupyterLab application directory is C :\ Users \ Pat \ Miniconda3 \ share \ jupyter \ lab
4 [...]
5 [ I 18:27:20.645 LabApp ] Interrupted ...
6 [ I 18:27:32.986 LabApp ] Shutting down 0 kernels
7 ( base ) PS C :\ Users \ Pat >
Il s’agit d’un comportement normal. Quand Jupyter est actif, vous n’avez plus la main dans l’interpréteur et tous ces
messages s’affichent. Une fois que vous quittez Jupyter, vous devriez récupérer la main dans l’interpréteur. Si ce n’est pas le
cas, pressez deux fois la combinaison de touches Ctrl + C
Si tous ces tests ont bien fonctionné, bravo, vous avez installé correctement Python avec Miniconda ainsi que tous les
modules qui seront utilisés pour ce cours. Vous pouvez quitter le shell en tapant exit puis en appuyant sur la touche Entrée
et aller faire une pause !
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 291 292 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
B.4. Choisir un bon éditeur de texte Annexe B. Installation de Python Annexe B. Installation de Python B.4. Choisir un bon éditeur de texte
Sauf cas exceptionnel, nous vous conseillons l’utilisation de conda pour gérer l’installation de modules supplémen-
taires.
Si vous souhaitez installer un paquet qui n’est pas présent sur un dépôt conda avec pip, assurez vous d’abord que votre
environnement conda est bien activé (avec conda activate ou conda activate nom_environnement). La syntaxe est
ensuite très simple :
1 $ pip install nom_du_paquet
Si votre environnement conda était bien activé lors de l’appel de cette commande, celle-ci aura installé votre paquet dans
l’environnement conda. Tout est donc bien encapsulé dans l’environnement conda, et l’ajout de tous ces paquets ne risque pas
d’interférer avec le Python du système d’exploitation, rendant ainsi les choses bien « propres ».
Ensuite, il est important de faire en sorte que Notepad++ affiche les numéros de ligne sur la gauche (très pratique lorsque
On configure ensuite gedit pour que l’appui sur la touche Tab corresponde à une indentation de 4 espaces, comme recom- l’interpréteur nous indique qu’il y a une erreur, par exemple, à la ligne 47). Toujours dans la fenêtre Préférences, dans
mandée par la PEP 8 (chapitre 15 Bonnes pratiques en programmation Python). Pour cela, cliquez sur l’icône en forme de 3 la liste sur la gauche cliquez sur Zones d'édition, puis sur la droite cochez la case Afficher la numérotation des
petites barres horizontales en haut à droite de la fenêtre de gedit, puis sélectionnez Préférences. Dans la nouvelle fenêtre qui lignes comme indiqué ici :
s’ouvre, sélectionnez l’onglet Éditeur puis fixez la largeur des tabulations à 4 et cochez la case Insérer des espaces au lieu des
tabulations : 7. https://notepad-plus-plus.org/download
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 293 294 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
B.5. Comment se mettre dans le bon répertoire dans le shell Annexe B. Installation de Python Annexe B. Installation de Python B.5. Comment se mettre dans le bon répertoire dans le shell
Sous Windows, il existe deux astuces très pratiques. Lorsqu’on utilise l’explorateur Windows et que l’on est dans un
répertoire donné :
8. http://www.barebones.com/products/textwrangler/
9. https://www.barebones.com/products/bbedit/
10. http://www.barebones.com/products/bbedit/download.html
11. https://www.barebones.com/support/bbedit/ Deuxième astuce
12. https://s3.amazonaws.com/BBSW-download/BBEdit_12.6.6_User_Manual.pdf
13. https://stackoverflow.com/questions/5750361/auto-convert-tab-to-4-spaces-in-textwrangler
14. https://www.sublimetext.com/
15. https://atom.io/
16. https://fr.wikipedia.org/wiki/Environnement_de_d%C3%A9veloppement
17. https://code.visualstudio.com/ En pressant la touche shift et en faisant un clic droit dans un endroit de l’explorateur qui ne contient pas de fichier (attention,
18. https://www.spyder-ide.org/ ne pas faire de clic droit sur un fichier !). Vous verrez alors s’afficher le menu contextuel suivant :
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 295 296 Cours de Python / Université Paris Cité / UFR Sciences du Vivant
B.5. Comment se mettre dans le bon répertoire dans le shell Annexe B. Installation de Python Annexe B. Installation de Python B.6. Python web et mobile
À votre tour !
Pour tester si vous avez bien compris, ouvrez votre éditeur favori, tapez les lignes suivantes puis enregistrez ce fichier avec
le nom test.py dans le répertoire de votre choix.
1 import tkinter as tk
2
3 racine = tk . Tk ()
4 label = tk . Label ( racine , text =" J ' adore Python !")
5 bouton = tk . Button ( racine , text =" Quitter " , command = racine . quit )
6 bouton [" fg "] = " red "
7 label . pack ()
8 bouton . pack ()
9 racine . mainloop ()
10 print (" C ' est fini !")
Comme nous vous l’avons montré ci-dessus, ouvrez un shell et déplacez-vous dans le répertoire où se trouve test.py.
Lancez le script avec l’interpréteur Python :
1 $ python test . py
Si vous avez fait les choses correctement, cela devrait afficher une petite fenêtre avec un message « J’adore Python ! » et
un bouton Quitter.
Vérification
La figure suivante montre le PowerShell, ouvert de la première ou la deuxième façon, dans lequel nous avons lancé la 19. https://repl.it/languages/python3
20. https://www.tutorialspoint.com/execute_python3_online.php
commande ls qui affiche le nom du répertoire courant (celui dans lequel on se trouve, dans notre exemple D:\PAT\Python)
21. http://pythontutor.com/visualize.html#mode=edit
ainsi que les fichiers s’y trouvant (ici il n’y a qu’un fichier : test.py). Ensuite nous avons lancé l’exécution de ce fichier 22. https://play.google.com/store/apps/details?id=ru.iiec.pydroid3
test.py en tapant python test.py. 23. https://itunes.apple.com/us/app/pythonista-3/id1085978097
Cours de Python / Université Paris Cité / UFR Sciences du Vivant 297 298 Cours de Python / Université Paris Cité / UFR Sciences du Vivant