Cours Python
Cours Python
n 3
rsio
Ve
1 Pourquoi Python ? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
2 Un programme Python . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9
3 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12
4 Valeurs et types de base . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
5 Structures de contrôle – Instructions, Conditions & Itérations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6 Structures de contrôle – Itérations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
7 Opérateurs arithmétiques et logiques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 16
8 Gestion des caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
Gestion des caractères : représentation interne et table de codage . . . . . . . . . . . . . . . . . . . . . 18
Gestion des caractères : avec ou sans codage . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19
Représentation d’un octet sous forme hexadécimale . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Gestion des accents : unicode et le codage UTF-8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Python et l’UTF-8 : chaîne de caractères vs chaîne d’octets . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
Opérations sur les chaînes de caractères et chaîne d’octets . . . . . . . . . . . . . . . . . . . . . . . . . . 28
Formater des données dans une chaîne de caractères . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
9 Listes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
Listes — Exemples d’utilisation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Mon’tit Python – P-F.B.
⋆ portable : disponible sous toutes les plate-formes (de Unix à Windows, en passant par des systèmes
embarqués avec MicroPython) ;
⋆ simple : possède une syntaxe claire, privilégiant la lisibilité, libérée de celle de C/C++ ;
⋄ programmation fonctionnelle : les fonctions sont dites «fonction de première classe», car elles
peuvent être fournies comme argument d’une autre fonction, il dispose aussi de lambda expres-
sion (fonction anonyme), de générateur etc.
Il est :
⋆ dynamique : il n’est pas nécessaire de déclarer le type d’une variable dans le source : elle sert à
référencer une donnée dont le type est connu lors de l’exécution du programme ;
⋆ fortement typé : les types sont toujours appliqués (un entier ne peut être considéré comme une
chaîne sans conversion explicite, une variable possède un type lors de son affectation).
⋆ compilé/interprété : le source est compilé en bytecode à la manière de Java (pouvant être sauvegar-
dé) puis exécuté sur une machine virtuelle ;
⋆ interactif : en exécutant l’interprète, on peut entrer des commandes, obtenir des résultats, travailler
sans avoir à écrire un source au préalable.
Il existe même des compilateurs vers C, CPython, vers la machine virtuelle Java (Jython), vers .NET
(IronPython) !
Il est utilisé comme langage de script dans PaintShopPro, Blender3d, Autocad, Labview, etc.
Pourquoi Python ? Ses usages 8
L’utilisation de bibliothèques pour résoudre les problèmes de TPs est formellement déconseillée
pour le départ !
2 Un programme Python 9
Mode interactif
Sur tout Unix, Python est disponible, il est intégré dans les commandes de base du système.
Sous la ligne de commande (shell), il suffit de lancer la commande «python3» pour passer en mode interactif :
entrer du code et en obtenir l’exécution, utiliser les fonctions intégrées (builtins), charger des bibliothèques etc
xterm
pef@borg:~$ python3
Python 3.8.10 (default, Jun 2 2021, 10:49:15)
[GCC 9.4.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 10+20
30
>>> _
30
>>> _*2
60
>>>
>>> help()
Documentation
Mon’tit Python – P-F.B.
Sous ce mode interactif, il est possible d’obtenir de la documentation en appelant la fonction help(), puis en
entrant l’identifiant de la fonction ou de la méthode.
prompt du shell
Dans le cas où la commande «python» exécute Python v3, au lieu de v2, vous pouvez utiliser la com-
mande «python» à la place de «python3».
Structure d’un source Python 11
Les commentaires
Les commentaires vont du caractère # jusqu’à la fin de la ligne.
Il n’existe pas de commentaire en bloc comme en C (/* ... */).
Les instructions
Chaque instruction s’écrit sur un ligne, il n’y a pas de séparateur d’instruction.
Si une ligne est trop grande, le caractère «\» permet de passer à la ligne suivante.
Les blocs d’instructions
Les blocs d’instruction sont matérialisés par des indentations : plus de «{» et «}» comme en C !
1 #!/usr/bin/python3 Le caractère «:» sert à introduire les blocs.
2
3 # les modules utilisés
4 import sys, socket
5 # le source utilisateur
6 if (a == 1) :
7 # sous bloc
8 # indenté (espaces ou tabulation)
Une variable doit exister avant d’être référencée dans le programme : il faut l’instancier avant de s’en servir, sinon
il y aura une erreur (une exception est levée comme nous le verrons plus loin).
print(a) # provoque une erreur car a n'existe pas
a = 'bonjour'
print(a) # fonctionne car a est définie
La variable est une référence vers un élément du langage
Et les pointeurs ?
Il n’existe pas de pointeur en Python : tous les éléments étant manipulés par référence, il n’y a donc pas besoin
de pointeurs explicites !
Mon’tit Python – P-F.B.
Les conditions
if <test1> :
<instructions1>
<instructions2>
elif <test2>:
<instructions3>
else:
<instructions4>
Attention
⊳ Faire toujours attention au décalage : ils doivent être identiques (même nombre de tabulations
ou d’espaces) !
⊳ Ne pas oublier le «:» avant le bloc indenté !
Mon’tit Python – P-F.B.
Lorsqu’une seule instruction compose la condition, il est possible de l’écrire en une seule ligne :
if a > 3: b = 3 * a
6 Structures de contrôle – Itérations 15
Les itérations
L’exécution du bloc d’instructions de la boucle while dépend d’une condition.
while <test>:
<instructions1>
<instructions2> Le «else» de la structure de contrôle n’est exécuté que si la
else :
<instructions3> boucle n’a pas été interrompue par un break.
La boucle «for» sera introduite plus loin dans le support pour le parcours des listes.
break
⟹ l’utilisation des ruptures de contrôle simplifie l’écriture, ce qui évite les erreurs !
Dans l’exemple, <condition2> n’est évaluée que si <condition1> n’est pas vraie.
7 Opérateurs arithmétiques et logiques 16
Arithmétique
+, -, *, /,//,% addition, soustraction, multiplication, division, division entière, modulo
+=,-=,... opération + affectation de la valeur modifiée
xterm
Mon’tit Python – P-F.B.
>>> 2//3
0
>>> 2/3
0.6666666666666666
8 Gestion des caractères 17
Il n’existe pas de type caractère mais seulement des chaînes contenant un caractère unique.
Une chaîne est délimitée par des ' ou des " ce qui permet d’en utiliser dans une chaîne :
le_caractere = 'c'
a = "une chaîne avec des 'quotes'" # ou 'une chaîne avec des "doubles quotes"'
print (len(a)) # retourne 28
Il est possible d’écrire une chaîne contenant plusieurs lignes sans utiliser le caractère '\n' qui corres-
pond au «retour à la ligne», «newline», en l’entourant de 3 guillemets :
texte =""" premiere ligne
deuxieme ligne"""
Pour pouvoir utiliser le caractère d’échappement «\» dans une chaîne, sans déclencher son interpré-
tation, il faut la faire précéder de r (pour raw) :
xterm
>>> une_chaine = r'pour passer à la ligne il faut utiliser \n dans une chaine'
>>> une_chaine
'pour passer à la ligne il faut utiliser \\n dans une chaine'
En particulier, ce sera important lors de l’entrée d’expressions régulières que nous verrons plus loin.
Mon’tit Python – P-F.B.
Concaténation
Il est possible de concaténer deux chaines de caractères avec l’opérateur + :
a = "ma chaine"+" complete"
Gestion des caractères : représentation interne et table de codage 18
Table de codage : concept et opérations
À chaque caractère ou symbole est associé un rang dans une table de codage :
⊳ la fonction ord() permet d’obtenir le rang d’un caractère ou symbole dans la table de codage ;
⊳ la fonction chr() permet d’obtenir le caractère ou symbole à partir de son rang dans la table de codage ;
Table de codage : composition
Deux contraintes opposées :
□ la table de codage doit être petite : consommer peu de place en mémoire ou lors des transferts réseaux ;
Exemple de table de codage pour les 26 lettres de l’alphabet latin :
a:0 b:1 c:2 d:3 e:4 f:5 g:6 h:7 i:8 j:9 26 symboles ⟹ 2 = 16 < 26 < 2 = 32
4 5
k:10 l:11 m:12 n:13 o:14 p:15 q:16 r:17 s:18 t:19 ⟹ il faut 5 bits pour coder en binaire tous les rangs de
la table et il reste 6 symboles supplémentaires.
u:20 v:21 w:22 x:23 y:24 z:25
□ la table de codage doit être grande : elle doit contenir l’ensemble des symboles pour exprimer :
⋄ des langues basées sur un alphabet et utilisant des diacritiques (français, grec, arabe, russe, sanskrit, etc.)
⋄ des langues basées sur des idéogrammes comme le chinois ou le japonais ;
⋄ d’autre symboles utilisées couramment : pictogrammes, © , ®, etc.
Table de codage : compromis entre occupation mémoire et nombre de symboles
Codage des rangs sur 8 bits, ou un octet ⟹ 28 = 256 rangs possibles dans la table de codage : de la place pour l’alphabet latin
en minuscule, majuscule, des nombres, des symboles comme les parenthèses, les accolades, les opérateurs arithmétiques, etc.
⟹ codage ANSI ou ASCII : c’est le choix le plus courant pour les ordinateurs jusqu’à il y a quelques années.
Table de codage : l’avenir ? une table de codage universelle et un codage du rang extensible
Mon’tit Python – P-F.B.
⊳ normaliser et internationaliser le classement des symboles : Unicode, «Universal Coded Character Set» ;
⊳ utiliser un rang extensible sur :
⋄ un octet, ou 8 bits, pour les caractères les plus courants utilisés dans la programmation et dans les «vieux» ordinateurs ;
⋄ plusieurs octets pour les rangs suivants associés aux différents symboles de toutes les langues.
⟹codage UTF-8, Unicode (or Universal Coded Character Set) Transformation Format – 8-bit.
Gestion des caractères : avec ou sans codage 19
Mais alors ? Un octet c’est quoi ?
Un octet ou 8 bits peut être :
□ une valeur numérique :
⋄ entier non signé de 0 à 255 ;
⋄ entier signé de -128 à 127 ;
□ un symbole dans un codage sur 8 bits comme l’ANSI ou l’ASCII ;
□ un symbole dans le codage UTF-8 s’il correspond aux symboles usuels ;
□ une portion de codage UTF-8 pour des symboles de langues tenant sur plusieurs octets ;
Qui décide ?
⊳ les opérations du langage de programmation que l’on utilise : utilise-t-il le codage UTF-8 ?
⊳ l’ordinateur que l’on utilise : sous Linux le codage est en UTF-8 ;
⊳ le programmeur quand il décide de manipuler ces octets avec la connaissance de leur origine, de
leur sémantique et des opérations de conversion qu’il applique dessus ;
Peut-on faire des erreurs ?
Oui !
Peut-on prendre «connaissance» d’un octet sans décider de ce qu’il est ?
Mon’tit Python – P-F.B.
128 64 32 16 8 4 2 1
= 64+32+8=104
La notation hexadécimale est la plus simple et la plus employée car elle permet de noter facilement des séquences
d’octets (chaque octet est noté sous forme de deux digits hexadécimaux ou quartets).
Gestion des accents : consommation mémoire et codage UTF-8 21
Codage étendu sur 8 bits «à l’ancienne» : un symbole tient sur un octet
Codage «ANSI» ou «ASCII» sur 7 bits de 0 à 127 et on compléte celles de 128 à 255 sur 8 bits avec, au choix :
⊳ codage «ISO-8859-1» ou «LATIN1» : permet de coder les caractères accentués des pays d’Europe de l’ouest.
Il ne permet pas de coder le symbole de l’euro «€», ni le «œ».
⊳ codage «Windows-1252» : permet de coder l’ensemble des symboles du français ainsi que le symbole de l’euro.
Codage UTF8 : un symbole tient sur un octet au minimum
□ un caractère non accentué dont la valeur associée suivant le code ASCII ou ANSI est entre 32 et 127 (soient 7 bits)
⟹ codé sur 1 octet ;
□ un caractère accentué ⟹ codé sur 2 octets ;
□ un caractère non latin ou un idéogramme ⟹ codé 2,3 ou 4 octets (6 au maximum).
⟹L’utilisation de caractères accentués change la taille des données et peut pertuber la manipulation des données sous
forme d’octets.
Sous le shell, la commande echo peut envoyer une chaîne contenant un «é», en entrée de la commande xxd pour
l’afficher sous notation hexadécimale (le «00000000:» désigne le décalage par rapport au début de la chaîne) :
xterm
pef@darkstar:/Users/pef $ echo -n 'é' | xxd
00000000: c3a9 .. chaque point correspond à un octet non représentable
xterm
L’idéogramme « » est codé sur 3 octets.
Les deux symboles signifient «ordinateur».
Mon’tit Python – P-F.B.
xterm
$ echo -n '€' | xxd
00000000: e282 ac ...
Attention
Sous Python 3 toutes les chaînes de caractères sont en unicode.
xterm
>>> a = 'été'
>>> len(a)
3
oui
afficher en hexadécimal
afficher caractère
'\x??'
Pourquoi obtient-on un «é» au final à l’écran alors qu’on a deux plusieurs octets de codage ?
Parce que le terminal sait traiter l’unicode, c-à-d le codage des deux octets vers un ’e’ avec un accent aigu.
Conversion : chaîne de caractères ⟺ chaîne d’octets 25
>>> bytes('é','utf8')
née du codage 'utf8'.
b'\xc3\xa9'
>>> bytes.fromhex('61')
b'a' hex() retourne une chaîne de carac-
>>> bytes('é','utf8').hex() tères contenant la représentation hexa-
'c3a9'
décimale.
Conversion chaîne vers valeur numérique : recommendations 27
Caractère unicode vers valeur numérique
xterm xterm
>>> ord('A') >>> chr(8364)
65 '€'
>>> ord('œ') >>> chr(339)
339 >254 ⟹ ne tient pas sur un octet 'œ'
>>> ord('€') >>> chr(65)
8364 'A'
>>> >254 ⟹ ne tient pas sur un octet
La stratégie pour gérer les données quelconques par octet ? deux possibilités
□ manipulation décimale
chaîne d’octets
chaîne unicode □ manipulation par groupe d’octets
codage UTF8
1 symbole⟹1 octet
Opérations sur les chaînes de caractères et chaîne d’octets 28
Il est possible d’insérer le contenu d’une variable dans une chaîne de caractères ou chaîne d’octets à l’aide de l’opéra-
teur «%» qui s’applique sur une liste de format à substituer :
xterm
>>> a = 120
>>> b = 'La valeur de %s est %d' % ('a',a) # b <- la chaîne 'La valeur de a est 120'
>>> b
'La valeur de a est 120'
(caractères ou octets).
etc.
Remarque : ces méthodes fonctionnent aussi sur des chaînes d’octets : b'la ligne\n'.splitlines().
Formater des données dans une chaîne de caractères 29
Opérateur «%» vs fonction «format»
Affichage d’une chaîne composée de deux arguments : La même chose mais aussi avec une inversion :
xterm xterm
>>> print ('%s %s'%('un', 'deux')) >>> print ('{} {}'.format('un', 'deux'))
un deux un deux
>>> print ('{1} {0}'.format('un', 'deux'))
Pour des nombres : deux un
xterm xterm
>>> '%d'% 42 >>> '{:d}'.format(42)
'42' '42'
>>> '%f'%3.1415926 >>> '{:f}'.format(3.1415926)
'3.141593 '3.141593'
'FF'
>>> format(2, '02X') ⊳ } identifiant de fin de format.
'02'
>>> format(10,'08b')
'00001010' Remarques : «format()» ne fonctionne que sur des
chaîne de caractères (UTF-8).
9 Listes 30
Une liste d’un seul élément, ('un'), correspond à l’élément lui-même, 'un'.
La fonction len() renvoie le nombre d’éléments de la liste.
xterm
Retrait du dernier élément >>> element = a.pop()
>>> print (element, a)
quatre [1, 'deux', 3]
xterm
Tri des éléments >>> b = [1, 4, 3]
>>> b.sort()
Attention : >>> c = a.sort()
>>> c
ils doivent être mutuellement comparables >>> b
[1, 3, 4]
Attention : sort() ne retourne pas la liste
xterm
Inversion de l’ordre des éléments >>> a.reverse()
>>> a
[3, 'deux', 1]
xterm
Retrait du premier élément >>> print (a.pop(0))
Mon’tit Python – P-F.B.
3
>>> a
['deux', 1]
Listes — Utilisation comme «pile» et «file» 32
Pour une approche «algorithmique» de la programmation, il est intéressant de pouvoir disposer des
structures particulières que sont les piles et files.
La pile
xterm
empiler ma_pile.append(element) >>> ma_pile = []
>>> ma_pile.append('sommet')
dépiler element = ma_pile.pop() >>> ma_pile
['sommet']
>>> element = ma_pile.pop()
>>> element
'sommet'
La file
xterm
enfiler ma_file.append(element) >>> ma_file = []
>>> ma_file.append('premier')
défiler element = ma_file.pop(0) >>> ma_file.append('second')
>>> element = ma_file.pop(0)
>>> element
'premier'
Mon’tit Python – P-F.B.
D’où le fameux accès indicé, commun au C, C++ ou Java : (ici, on parcourera les valeurs 0,1,2,3 et 4)
xterm
>>> a = ['un','deux','trois']
Mon’tit Python – P-F.B.
En particulier, cela est utile pour les fonctions retournant plusieurs valeurs.
Opérateur d’appartenance
L’opérateur in permet de savoir si un élément est présent dans une liste.
xterm
>> 'a' in ['a', 'b', 'c']
True
C’est l’opérateur «in» que l’on utilisera pour tester l’existence d’un élément dans un objet.
Création automatique de liste
Mon’tit Python – P-F.B.
xterm
>>> ['a']*10
['a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a']
Utilisation avancée : création d’une liste à partir d’une autre 35
Il est possible d’obtenir une deuxième liste à partir d’une première, en appliquant une opération sur
chaque élément de la première .
La deuxième liste contient le résultat de l’opération pour chacun des éléments de la première liste.
Une notation particulière permet en une instruction de combiner la création de cette deuxième liste et
le parcours de la première.
Exemple :
on cherche à obtenir la liste des lettres en majuscule à partir des valeurs ASCII de 65 (’A’) à 91 (’Z’) :
xterm
>>> [chr(x) for x in range(65, 91)]
['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q',
'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z']
Cette forme de création de liste à partir d’une liste s’appelle les «lists comprehension».
xterm
Mon’tit Python – P-F.B.
En C : En Python :
a = (condition ? 1 : 0); contenu = ((doc + '\n') if doc else '')
x = true_value if condition else false_value
Opérateur ternaire et les «lists comprehension»
⊳ Choix de l’élément à ajouter : on ajoute le caractère si le code ASCII qui lui correspond est impair (le modulo vaut 1 ce qui
équivaut à vrai), sinon on ajoute une chaîne vide ''.
xterm
>>> l=range(65,90) Pourquoi appliquer la fonction list() ? Pour forcer la création de la liste !
>>> list(l)
[65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
87, 88, 89]
>>> [chr(x) if (x % 2) else '' for x in l ]
['A', '', 'C', '', 'E', '', 'G', '', 'I', '', 'K', '', 'M', '', 'O', '', 'Q', '', 'S', '',
'U', '', 'W', '', 'Y']
⊳ Ajout conditionnel d’un élément : on ajoute le caractère suivant le même test que précédemment, mais dans le cas où la
condition est fausse, on n’ajoute rien à la liste résultat !
xterm
>>> l=range(65,90)
>>> list(l)
[65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86,
87, 88, 89]
>>> [chr(x) for x in l if (x % 2)]
['A', 'C', 'E', 'G', 'I', 'K', 'M', 'O', 'Q', 'S', 'U', 'W', 'Y']
Remarque
Mon’tit Python – P-F.B.
Certaines fonctions Python comme range() font de l’évaluation paresseuse, «lazy evaluation», c-à-d qu’elles ne calculent
leur résultat que lorsqu’il est nécessaire, d’où le list().
Sinon print(range(0,10)) ne renverrait que range(0,10) .
Tableau & liste modifiable 37
Créer les éléments du tableau
Pour pouvoir traiter une liste à la manière d’un tableau, il faut en créer tous les éléments au préalable :
xterm
>>> t = [0]*10
>>> t
[0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
Ici, on vient de créer un tableau à deux dimensions de 5 lignes de 4 colonnes (accès avec t[a][b]).
Accès par indice aux éléments d’une chaîne 38
Rapport entre une liste et une chaîne de caractères ? Aucun !
Elles bénéficient de l’accès par indice, par tranche et du parcours avec for :
a = 'une_chaine'
b = a[4:7] # b reçoit 'cha'
Pour pouvoir modifier une chaîne de caractère, il n’est pas possible d’utiliser l’accès par indice :
xterm
>>> a='le voiture'
>>> a[1] = 'a'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>> b = ''.join(a)
>>> print (b)
indique le séparateur à insérer entre les caractères, ici il est vide ''
la voiture
Accès par indice aux éléments d’une chaîne d’octets et la boucle for 39
Et pour les chaînes d’octets ?
xterm
>>> chaine_octets = b'ABC' L’accès par indice dans une chaîne d’octets retourne
>>> print(chaine_octets)
b'ABC'
le rang du caractère !
>>> chaine_octets[0]
65
C’est équivalent à :
xterm
>>> ord(b'A')
65
Chaque élément parcouru par la boucle for est retourné sous forme de son rang.
Et les tranches de chaîne d’octets ?
Mon’tit Python – P-F.B.
xterm
>>> b'abcdef'[2:3]
b'c'
>>> b'abcdef'[2:5]
b'cde'
Ces objets permettent de conserver l’association entre une clé et une valeur.
Ce sont des tables de hachage pour un accès rapide aux données :
⋄ La clé et la valeur peuvent être de n’importe quel type non modifiable.
⋄ La fonction len() retourne le nombre d’associations du dictionnaire.
Liste des opérations du dictionnaire
Initialisation dico = {}
définition dico = {'un': 1, 'deux' : 2}
accès b = dico['un'] # recupere 1
interrogation if 'trois' in dico:
ajout ou modification dico['un'] = 1.0
suppression del dico['deux']
récupère la liste des clés les_cles = list(dico.keys())
récupère la liste des valeurs les_valeurs = list(dico.values())
Attention
Les éléments d’un dictionnaire ne sont pas triés !
Ils ne sont pas triés dans l’ordre d’ajout.
On utilise la fonction sorted en lui donnant une fonction d’accès à la clé de tri :
xterm
>>> sorted(liste_des_éléments_du_dico,key=lambda t:t[1])
[('a', 1), ('e', 3), ('d', 5), ('f', 10)]
La fonction d’accès est donnée par une «lambda fonction» ou une fonction anonyme définie en une ligne.
Utilisation des listes et dictionnaires 42
Couples de valeurs obtenus par combinaison de deux listes
xterm
>>> list(zip(['a','b','c'],[1,2,3]))
[('a', 1), ('b', 2), ('c', 3)]
Il est également possible d’obtenir un dictionnaire utilisant chacun des couples en tant que (clé,valeur) :
xterm
>>> couples=zip(['a','b','c'],[1,2,3])
>>> dict(couples)
{'a': 1, 'b': 2, 'c': 3}
Attention : les valeurs d’une liste qui ne sont pas associées à une valeur dans la seconde, sont supprimées :
xterm
>>> list(zip(['a','b','c'],[1,2,3,4]))
[('a', 1), ('b', 2), ('c', 3)]
>>> list(zip(['a','b','c','d'],[1,2,3]))
Mon’tit Python – P-F.B.
list() permet d’obtenir le contenu complet pour l’affichage (évaluation paresseuse de zip())
11 Modules et espace de nom 43
Un module regroupe un ensemble cohérent de fonctions, classes objets, variables globales (pour définir
par exemple des constantes).
Chaque module est nommé : ce nom définit un espace de nom.
En effet, pour éviter des collisions dans le choix des noms utilisés dans un module avec ceux des autres
modules, on utilise un accès préfixé par le nom du module :
nom_module.element_defini_dans_le_module
Il existe de nombreux modules pour Python capable de lui donner des possibilités très étendues.
Accès à un module
Il se fait grâce à la commande import.
# quelques exemples
os.exit() # terminaison du processus
socket.SOCK_STREAM # une constante pour la programmation réseaux
Mon’tit Python – P-F.B.
Installation de nouveaux modules et utilisation simplifiée 44
xterm
$ python3 -c "import sys, urllib.parse as ul; print(ul.unquote(sys.argv[1]))"
Permet de décoder les URLS contenant du «percent-encoding» (%20 pour un espace, etc)
12 Sorties écran 45
La fonction print() permet d’afficher de manière générique tout élément, que ce soit un objet, une
chaîne de caractères, une valeur numérique, etc :
⊳ le passage d’une liste permet de «coller» les affichages sur la même ligne :
xterm
>>> a = 'bonjour'
>>> c = 12
>>> d = open('fichier.txt', 'w')
>>> print (a)
bonjour
>>> print (c,d, 'la valeur est %d' % c) 1
12 <_io.TextIOWrapper name='fichier.txt' mode='w' encoding='UTF-8'> la valeur est 12
import sys
sys.stdout.write('Hello\n')
13 Entrées clavier 46
La fonction input()
Pour la saisie des données au clavier, la fonction input() retourne un chaîne de caractères au format UTF-8,
que l’on convertira au besoin.
1 saisie = input("Entrer ce que vous voulez :") # retourne une chaîne de caractères
xterm
>>> saisie = input("Entrer ce que vous voulez :")
Entrer ce que vous voulez :Python 3 c'est super !
>>> saisie
"Python 3 c'est super !"
Pour obtenir une valeur entière, il est nécessaire de convertir la valeur saisie :
xterm
>>> saisie = input("Entrer une valeur :")
Entrer une valeur :10
>>> saisie
'10'
>>> int(saisie)
10
Si la chaîne de caractères rentrées contient autre chose que la valeur à convertir, une exception est levée :
xterm
>>> saisie = input("Entrer une valeur :")
Entrer une valeur :la valeur est 10 dans cet exemple
>>> int(saisie)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
Mon’tit Python – P-F.B.
ValueError: invalid literal for int() with base 10: 'la valeur est 10 dans cet exemple'
Attention
La chaîne retournée par la fonction «input()» ne contient pas le '\n'.
14 Conversions de types 47
Un certain nombre de fonctions permettent de convertir les données d’un type à l’autre.
La fonction type() permet de récupérer le type de la donnée sous forme d’une chaîne.
Conversion utf8 vers chaîne d’octet puis vers rang de chaque caractère
>>> bytes('é','utf8')
b'\xc3\xa9'
>>> list(bytes('é','utf8'))
[195, 169]
>>> [hex(x) for x in list(bytes('é','utf8'))] # on vérifie que les valeurs sont les bonnes
['0xc3', '0xa9']
Conversion en représentation binaire
Convertir un nombre exprimé en format binaire dans une chaîne de caractères :
Mon’tit Python – P-F.B.
∘ avec le type bytes et sa méthode hex(), on obtient la représentation hexadécimale de chaque caractère :
xterm
>>> bytes('été','UTF-8').hex()
'c3a974c3a9'
>>> b'abcABC\n\t'.hex()
'6162634142430a09'
∘ passer d’une valeur exprimée en notation hexadécimale vers un entier, puis en binaire avec bin() :
xterm
>>> int('ef6263c142430a09',16)
Mon’tit Python – P-F.B.
17249459204473948681
>>> bin(int('ef6263c142430a09',16))
'0b1110111101100010011000111100000101000010010000110000101000001001'
>>> int('0b1110111101100010011000111100000101000010010000110000101000001001',2)
17249459204473948681
Attention de bien faire la distinction entre ces différentes notations !
Mélange chaîne d’octet, «b' '» et chaîne de caractères, «' '» 49
La conversion vers une représentation «chaîne de caractères»
xterm
>>> liste = [2, 3]
>>> str(liste)
'[2, 3]' représentation de la liste en chaîne de caractère
>>> bytes(liste)
b'\x02\x03' conversion de chaque entier en chr(entier)
>>> liste = [2, 'yop']
>>> bytes(liste)
Traceback (most recent call last): ne marche pas car un élément de la liste n’est pas entier
File "<stdin>", line 1, in <module>
TypeError: 'str' object cannot be interpreted as an integer
xterm
>>> f=open('.bashrc','r')
>>> str(f)
"<_io.TextIOWrapper name='.bashrc' mode='r' encoding='UTF-8'>"
>>> bytes(f)
Traceback (most recent call last): convertir tout objet vers une chaîne de caractère mais pas vers une chaîne d’octets
File "<stdin>", line 1, in <module>
TypeError: 'str' object cannot be interpreted as an integer
>>>
15 Quelques remarques 51
if (a = ma_fonction()):
# opérations
La commande format :
representation_binaire = format(5,'b') # ici, on obtient '101'
La séquence binaire retournée commence au premier bit à 1 en partant de la gauche.
Pour obtenir une représentation binaire sur 8bits, il faut la préfixer avec les '0' manquants :
rep_binaire = format(5,'08b') # ce qui donne '00000101'
Mon’tit Python – P-F.B.
Python utilise le mécanisme des exceptions : lorsqu’une opération ne se déroule pas correctement,
une exception est levée ce qui interrompt le contexte d’exécution, pour revenir à un environnement
d’exécution supérieur. Ce processus est répété jusqu’à un contexte gérant cette exception, ou jusqu’à
l’arrêt du programme s’il n’y en a pas.
Par défaut, l’environnement supérieur est le shell de commande depuis lequel l’interprète Python a été
lancé, et le comportement de gestion par défaut est d’afficher l’exception :
xterm
Traceback (most recent call last):
File "test.py", line 1, in ?
3/0
ZeroDivisionError: integer division or modulo by zero
Toutes les opérations susceptibles d’entraîner une erreur ne lève pas d’exception.
Gestion des erreurs & Exceptions 53
Traiter une exception
Elles sont traitées, «interceptées», suivant leur nature :
nombre = input( "Entrer valeur: " )
try:
nombre = float( nombre )
resultat = 20.0 / nombre
except ValueError:
print ("Vous devez entrer un nombre")
except ZeroDivisionError:
print ("Essai de division par zéro")
print ("%.3f / %.3f = %.3f" % ( 20.0, nombre, resultat ))
Question : est-ce que toutes les exceptions sont gérées dans cet exemple ?
Il existe de nombreux types d’exception correspondant à des classes objet héritant de la classe racine
Exception.
La définition de ses propres exceptions est en dehors du domaine d’application de ce cours.
La fonction "open" renvoie un objet de type file et sert à ouvrir les fichiers en :
"r" lecture lève une exception en cas d’erreur
"w" écriture le fichier est créé s’il n’existe pas, sinon il est écrasé
"a" ajout le fichier est créé s’il n’existe pas, sinon il est ouvert et l’écriture se fait à la fin
UTF-8 vs octets
Par défaut, l’ouverture ou la création d’un fichier est faite en codage UTF-8 : une lettre accentuée lue ou écrite reste
un symbole UTF-8.
Pour ouvrir ou créer le fichier au format octet, «bytes», on utilise le suffixe «b» : "rb", "wb" ou "ab" : une lettre
accentuée lue ou écrite donne deux octets.
Pour vérifier que l’ouverture du fichier se fait correctement, il faut traiter une exception.
try:
fichier = open("lecture_fichier.txt","r")
except Exception as e:
print (e.args)
Ce qui peut produire : Description de l’erreur
[Errno 2] No such file or directory: 'lecture_fichier.txt'
Mon’tit Python – P-F.B.
On utilisera le type de la classe racine Exception pour intercepter l’exception, car on attend ici qu’une seule erreur.
Dans le cas où l’on veut gérer plusieurs exceptions de types différents pouvant être levées dans un bloc d’instruction, il
faut indiquer leur type respectif.
Fichiers : UTF-8 vs octets 55
Création d’un fichier en codage UTF-8 et lecture sous forme d’octets
#!/usr/bin/python3 1 ⇒ouverture en écriture au format UTF-8 par
import sys
défaut ;
try: 1
2 ⇒ouverture en lecture au format binaire.
f = open("fichier_test", "w")
except Exception as e: Attention
print(e.args)
sys.exit(1) La chaîne retournée par la méthode «read-
f.write('été')
line()» contient le '\n'.
f.close()
2
f = open("fichier_test", "rb")
ligne = f.readline()
print(ligne)
xterm
$ xxd fichier_test
00000000: c3a9 74c3 a9 ..t..
Le fichier contient 5 octets : 2 octets pour chaque 'é' et 1 octet pour le 't'.
Fichiers : lecture par ligne 56
L’objet de type file peut être utilisé de différentes manières pour effectuer la lecture d’un fichier.
□ comme une liste, ce qui permet d’utiliser le for :
for une_ligne in fichier:
print (une_ligne) ⟹ Déconseillé, on ne l’utilisera pas...
□ comme un «itérateur» sur lequel on applique la fonction next() (qui lève une exception à la fin) :
while 1:
try:
# renvoie l'exception StopIteration ⟹ Déconseillé, on ne l’utilisera pas...
# à la fin
une_ligne = next(fichier)
print (une_ligne)
except:
break
une_ligne = fichier.readline()
if not une_ligne:
break
ligne = ligne.rstrip('\n')
Fichiers : lecture caractère par caractère, ajout et positionnement 57
Lecture caractère par caractère : read vs readline
Sans argument, la méthode readline renvoie la prochaine ligne du fichier.
Avec l’argument n, cette méthode renvoie n caractères au plus (jusqu’à la fin de la ligne).
Autres méthodes
read(n) lit n caractères quelconques (même les \n) dans le fichier
fileno() retourne le descripteur de fichier numérique
readlines() lit et renvoie toutes les lignes du fichier
Mon’tit Python – P-F.B.
Les données structurées correspondent à une séquence d’octets : composée de groupes d’octets dont
le nombre correspond au type de la variable.
En C ou C++ : struct exemple {
int un_entier; # 4 octets
float un_flottant[2]; # 2*4 = 8 octets
char une_chaine[5]; # 5 octets
} # la structure complète fait 17 octets
En Python, les structures de cette forme n’existent pas et une «chaîne d’octets» sert à manipuler cette
séquence d’octets.
Le module spécialisé struct permet de composer ou de décomposer cette séquence d’octets suivant
les types contenus. Exemple : un entier sur 32bits correspond à une chaîne de 4 caractères.
Pour décrire la structure à manipuler, on utilise une chaîne de format où des caractères spéciaux ex-
priment les différents types qui se succèdent et permettent de regrouper les octets entre eux.
b'\n\x00\x00\x00\x14\xae6B\x9a\x99\xc4Babcde'
>>> liste_valeurs = struct.unpack('=i2f5c', données_compactées)
>>> liste_valeurs
(10, 45.66999816894531, 98.30000305175781, b'a', b'b', b'c', b'd', b'e')
Attention : le format ’5c’ renvoie 5 caractères alors que ’5s’ renvoie une chaîne de 5 caractères.
18 Expressions régulières ou expressions rationnelles 60
Une expression régulière est exprimée par une suite de meta-caractères, exprimant :
⊳ une position pour le motif ⊳ une alternative
^ : début de chaîne | : ceci ou cela, exemple : a|b
$ : fin de chaîne
⊳ un caractère
. : n’importe quel caractère
[ ] : un caractère au choix parmi une liste, exemple : [ABC]
[^ ] : tous les caractères sauf..., exemple : [^@] tout sauf le «@»
[a-zA-Z] : toutes les lettres minuscules et majuscules
⊳ des quantificateurs, qui permettent de répéter le caractère qui les précédent :
* : zéro, une ou plusieurs fois
+ : une ou plusieurs fois { n } : n fois
? : zéro ou une fois { n, m } : entre n et m fois
⊳ des familles de caractères :
Mon’tit Python – P-F.B.
⇓
xterm
trouvé !
<_sre.SRE_Match object; span=(0, 2), match='12'>
12
Mon’tit Python – P-F.B.
UTF-8 et octets
□ Pour rechercher dans une chaîne de caractères : le motif ou ER doit être une chaîne de ca-
ractères.
□ Pour rechercher dans une chaîne d’octets : le motif doit être une chaîne d’octets.
import re
une_chaine = "Ma saison préférée est l'été, mais le printemps est pas mal non plus"
re_mot = re.compile(r"(\w*é\w*)")
resultat = re_mot.findall(une_chaine)
if resultat :
print (resultat)
La méthode findall renvoie une liste de toutes les occurences, ici, des mots contenant un ’é’
xterm
$ python3 er2.py
['préférée', 'été']
import re
une_chaine = b'La valeur 12 est un nombre'
Mon’tit Python – P-F.B.
re_nombre = re.compile(rb"(\d+)")
resultat = re_nombre.search(une_chaine)
if resultat :
print (resultat.group(1))
on utilise le préfixe 'rb' pour indiquer une chaîne d’octets et bloquer l’interprétation des \
ER – Compléments : gestion du motif 63
Différence majuscule/minuscule
Pour ne pas en tenir compte, il faut l’indiquer avec une constante de module en argument :
re_mon_expression = re.compile(r"Valeur\s*=\s*(\d+)", re.I)
Motifs mémorisés
Il est possible de récupérer la liste des motifs mémorisés :
import re
chaine = 'Les valeurs sont 10, 56 et enfin 38.'
re_mon_expression = re.compile(r"\D*(\d+)\D*(\d+)\D*(\d+)", re.I)
resultat = re_mon_expression.search(chaine)
if resultat :
liste = resultat.groups()
for une_valeur in liste:
print (une_valeur)
⇓
xterm
10
56
38
Mon’tit Python – P-F.B.
ER – Compléments : éclatement et recomposition 64
Décomposer une ligne
Il est possible "d’éclater" une ligne suivant l’ER représentant les séparateurs :
import re
chaine = 'Arthur:/::Bob:Alice/Oscar'
re_separateur = re.compile( r"[:/]+" )
liste = re_separateur.split(chaine)
print (liste)
⇓
xterm
['Arthur', 'Bob', 'Alice', 'Oscar']
xterm
['Mon', 'chat', "s'appelle", 'Neko']
Mon_chat_s'appelle_Neko
Ici, la chaîne contient le séparateur qui sera ajouté entre chaque élément de la liste.
19 Fonctions : définition & arguments 65
print (variable_a_modifier)
⇓
xterm ⇓
Alice xterm
Bob
Fonctions : valeur de retour & 𝜆-fonction 66
Plusieurs valeurs de retour
def ma_fonction(x,y):
return x*y,x+y
# code principal
produit, somme = ma_fonction(2,3)
liste = ma_fonction(5,6)
print (produit, somme)
print (liste)
⇓
xterm
6 5
(30,11)
En combinaison avec la fonction filter() qui applique une fonction anonyme sur chaque élément
d’une liste et retourne la liste des résultats :
xterm
Mon’tit Python – P-F.B.
Ici, sont filtrés les éléments pour lesquels la valeur de retour de la lambda fonction donne False ou 0.
20 Contrôle d’erreur à l’exécution 67
Une forme simple de contrôle d’erreur est introduite grâce à la fonction assert :
assert un_test, une_chaine_de_description
Fonctionnement de l’assert
Si la condition de l’assert n’est pas vérifiée alors le programme lève une exception.
try:
a = 10
assert a<5, "mauvaise valeur pour a"
except AssertionError as e:
print ("Exception: ",e.args)
⇓
xterm
Exception: ('mauvaise valeur pour a',)
⊳ les conditions des «assert» écrites dans le source fournissent des informations sur les données : le
programme est mieux documenté ;
⊳ une fois le programme testé, le mécanisme d’assert peut être désactivé afin de supprimer les tests
et leur impact sur le temps d’exécution du programme.
21 Génération de valeurs aléatoires : le module random 68
Choix d’une valeur numérique aléatoire dans un intervalle
import random
import random
xterm
B
22 Intégration dans Unix : l’écriture de Script système 69
Lorsque l’on écrit un programme Python destiné à être utilisé en tant que «script système», c-à-d comme
une commande, il est important de soigner l’interface avec l’utilisateur, en lui proposant des choix par
défaut lors de la saisie de paramètres :
1 #!/usr/bin/python3
2 import sys
3
4 #configuration
5 nom_defaut = "document.txt"
6
7 #programme
8 saisie = input("Entrer le nom du fichier [%s]" % nom_defaut)
9 nom_fichier = saisie or nom_defaut
10
11 try:
12 entree = open(nom_fichier, "r")
13 except Exception as e:
14 print (e.args)
15 sys.exit(1)
⊳ ligne 4 : on définie une valeur par défaut pour le nom du fichier à ouvrir ;
⊳ ligne 6 : on saisie le nom de fichier avec, entre crochets, le nom par défaut ;
⊳ ligne 7 : si l’utilisateur tape directement «entrée», saisie est vide, c-à-d considérée comme
Mon’tit Python – P-F.B.
fausse, et et l’opérateur «or» affecte la valeur par défaut, qui, elle, est considérée comme vraie.
23 Gestion de processus : lancer une commande externe et récupérer son résultat 70
La méthode communicate() :
⊳ transmets les données à la commande externe sur stdin et ferme stdin de la commande externe ;
⊳ lit toutes les sorties de la commande externe et attends la fin de l’exécution de la commande ;
⊳ retourne la sortie complète de la commande externe et sa valeur de succès.
Gestion de processus : création d’un second processus 71
Scinder le processus en deux
La commande fork permet de scinder le processus courant en deux avec la création d’un nouveau
processus. L’un est désigné comme étant le père et l’autre, le fils.
import os, sys
pid = os.fork()
if not pid :
# je suis l'enfant
print("je suis l'enfant")
else:
# je suis le père
os.kill(pid, 9) # terminaison du processus fils
print (sys.argv)
Si on lance ce script :
xterm
Mon’tit Python – P-F.B.
exécution
clonage né» en un nouveau processus 𝑃1 .
exécution
temps
père) ;
Système
E/S
□ sont indépendants : après le fork, toute entrée/sor- de
fichiers
stdout stderr
tie créée n’est pas partagées.
Mon’tit Python – P-F.B.
24 Programmation Socket : protocole TCP 73
Utilisation du protocole TCP
Une connexion TCP correspond à un tube contenant deux canaux, un pour chaque direction de com-
munication (A vers B, et B vers A).
Les échanges sont bufférisés : les données sont stockées dans une mémoire tampon jusqu’à ce que
le système d’exploitation les envoie dans un ou plusieurs datagrammes IP.
Les primitives de connexion pour le protocole TCP : socket, bind, listen, accept, connect,
close, shutdown.
⟹ C’est cette opération qu’il faut utiliser car elle envoi immédiatement
les données !
Attention : Les opérations de lecture et d’écriture utilisent des chaînes d’octets b''.
Modèle «client/serveur» avec TCP 74
while 1:
ligne = ma_socket.recv(1024) # réception d'au plus 1024 caracteres
if not ligne:
break
print (ligne) retourne une chaîne d’octets b''
ma_socket.close()
Attention
Mon’tit Python – P-F.B.
numero_port = 6688
ma_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
ma_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
ma_socket.bind(('', numero_port)) # équivalent à INADDR_ANY en C
ma_socket.listen(socket.SOMAXCONN)
socket retournée par le accept()
while 1:
(nouvelle_connexion, TSAP_depuis) = ma_socket.accept()
print ('Nouvelle connexion depuis ', TSAP_depuis)
nouvelle_connexion.sendall(b'Bienvenu\n')
nouvelle_connexion.close()
chaîne d’octets !
ma_socket.close()
Attention
Si vous échangez entre un client et un serveur, et que l’un attend de recevoir avant de répondre,
les deux processus peuvent se bloquer si l’envoi est retardé (bufférisé) et non immédiat.
COMPLÉMENT
Programmation Socket : TCP & bufférisation 78
⊳ les échanges sur Internet sont asynchrones : les données échangées sont reçues et envoyées sous forme de datagramme
IP, qui sont acheminés sans garanties d’ordre et de temps ;
⊳ le système d’exploitation améliore la situation en introduisant un buffer à la réception et à l’envoi ;
⊳ la programmation réseau est synchrones, mais sur ces buffers d’envoi et de réception.
Pour la réception
donnees = ma_socket.recv(1024) peut retourner moins d’octets mais pas plus de 1024.
Exemple :
⋆ la machine A envoie à la machine B, 30 lignes de texte pour un total de 920 octets ;
⋆ lors du transfert dans le réseau, ces 920 octets sont décomposés en un datagramme de 500 octets et un autre de 420
octets ;
⋆ lorsque B reçoit les 500 octets, le buffer de réception se remplit et les données sont mises à disposition du programme ;
⋆ la méthode recv ne retourne que 500 octets au programme.
Solution : tester le nombre d’octets obtenus en retour de l’appel à la méthode recv.
Pour l’envoi
nb_octets = ma_socket.send(data) les données sont mises dans le buffer d’envoi, et lorsqu’il y en aura suffi-
samment pour remplir un datagramme, ce datagramme sera réellement envoyé sur le réseau.
Il se peut que l’utilisation de la méthode send ne transmette rien sur le réseau et donc, le récepteur ne recevra rien et ne
réagira pas.
Solution : utiliser l’instruction sendall() au lieu de send(), pour forcer l’envoi immédiat des données.
Ces protocoles échangent des données structurées sous forme de lignes (séparées par des ’\r\n’).
Il faut vérifier les données reçues et éventuellement les concaténer aux suivantes pour retrouver une ligne complète.
Chaque ligne doit être envoyée immédiatement sans bufférisation.
Programmation Socket : lecture par ligne 79
Lecture d’une ligne de protocole orienté texte comme HTTP, SMTP, POP etc.
Lorsque l’on lit les informations reçues sur la socket TCP, on récupère des données découpées suivant des
blocs de taille quelconque, on ne récupère pas ces données ligne par ligne depuis la socket.
Il est nécessaire de définir une fonction renvoyant une ligne lue caractère par caractère :
def lecture_ligne(ma_socket):
ligne = b''
while 1:
caractere_courant = ma_socket.recv(1)
if not caractere_courant :
break
ligne += caractere_courant
if caractere_courant == b'\n':
break
return ligne
La ligne retournée par la fonction inclut le retour à la ligne : b'\r\n' ou b'\n'.
Le module select et sa fonction select() permet d’être averti de l’arrivée d’événements sur des
descripteurs de fichier ou des sockets.
Ainsi, il est possible de ne plus se bloquer en lecture, voire en écriture, sur tel ou tel descripteur ou
socket.
Ces événements sont :
⋆ une demande de connexion, lorsque cela concerne à une socket serveur ;
⋆ la présence de données à lire ;
⋆ la possibilité d’écrire sans être bloqué (le récepteur ne bloquera pas l’émetteur).
Il faut fournir en argument de select trois listes de descripteurs ou socket, correspondant à la caté-
gorie des événements :
1. en entrée (lecture ou connexion), 3. exceptionnels (généralement vide)
2. en sortie,
La fonction select retourne les trois listes modifiées, c-à-d ne contenant que les descripteurs pour
lesquels un événement est survenu.
import select
(evnt_entree,evnt_sortie,evnt_exception) = select.select(surveil_entree,[],[])
L’appel à la méthode select bloque tant qu’aucun événement n’est survenu.
Mon’tit Python – P-F.B.
Au retour de la fonction, il suffit de parcourir le contenu de ces listes pour trouver les descripteurs/so-
ckets à traiter (par exemple, trouver une socket où des données sont lisibles).
Pour détecter une demande de connexion, il faut comparer chaque socket de la liste evnt_entree
à la socket utilisée pour faire l’opération «accept».
Programmation socket : select() 82
adresse_hote = ''
numero_port = 6688
ma_socket = socket.socket(socket.AF_INET,socket.SOCK_STREAM,socket.IPPROTO_TCP)
ma_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR,1)
ma_socket.bind((adresse_hote, numero_port))
ma_socket.listen(socket.SOMAXCONN)
surveillance = [ma_socket]
while 1:
(evnt_entree,evnt_sortie,evnt_exception) = select.select(surveillance,[],[])
for un_evenement in evnt_entree:
if (un_evenement == ma_socket):
# il y a une demande de connexion
nouvelle_connexion, depuis = ma_socket.accept()
print ("Nouvelle connexion depuis ", depuis)
nouvelle_connexion.sendall(b'Bienvenu\n')
surveillance.append(nouvelle_connexion)
continue
# sinon cela concerne une socket connectée à un client
ligne = un_evenement.recv(1024)
Mon’tit Python – P-F.B.
if not ligne :
surveillance.remove(un_evenement) # le client s'est déconnecté
else :
print (un_evenement.getpeername(),':',ligne)
# envoyer la ligne a tous les clients, etc
25 Programmation socket : le protocole UDP 83
Utilisation du protocole UDP :
import socket
ma_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM,socket.IPPROTO_UDP)
ma_socket.bind(TSAP_local)
26 Multithreading – Threads 84
La classe «threading»
Cette classe permet d’exécuter une fonction en tant que thread.
import threading
def ma_fonction():
# travail
print('Travail de la thread')
return
# Déclenchement de la thread
ma_thread = threading.Thread(target = ma_fonction)
ma_thread.start()
# Thread principale
print('Travail de la thread principale')
Mon’tit Python – P-F.B.
⇓
xterm
Travail de la thread
Travail de la thread principale
COMPLÉMENT
Multithreading – Sémaphores 85
La classe semaphore, pour la protection des accès concurrents
Les méthodes sont :
Semaphore(val) fonction de classe retournant un objet Semaphore initialisé à la valeur option-
nelle ’value’
BoundedSemaphore(v) fonction de classe retournant un objet Semaphore initialisé à la valeur option-
nelle ’value’ qui ne pourra jamais dépasser cette valeur
acquire() essaye de diminuer la sémaphore, bloque si la sémaphore est à zéro
release() augmente la valeur de la sémaphore
import threading
def ma_fonction():
# travail
print("Travail de la thread")
s.release()
return
s = threading.Semaphore(0)
# Déclenchement de la thread
ma_thread = threading.Thread(target = ma_fonction)
ma_thread.start()
Mon’tit Python – P-F.B.
# Thread principale
print('Travail de la thread principale')
s.acquire()
27 Manipulations avancées : serveur Web intégré 86
Serveur Web
Le serveur Web va servir le contenu du répertoire courant depuis lequel on lance la commande :
xterm
pef@darkstar:/Users/pef $ python3 -m http.server
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...
127.0.0.1 - - [12/Aug/2018 21:33:47] "GET / HTTP/1.1" 200 -
</head>
Pour disposer d’un serveur Web avec exécution de scripts CGI dans le sous-répertoire cgi-bin/ :
xterm
$ python3 -m http.server --cgi
Il faut que les scripts soient exécutables (chmod +x) et qu’ils produisent en sortie un contenu adapté (HTML, JSON).
Manipulations avancées : traitement de données au format JSON 87
Pour traiter des résultats au format JSON
Dans le shell : Dans un programme :
La commande «curl» va récupérer les données au format JSON xterm
et ces données vont être formatées par le module «json.tool» : import json
from urllib.request import urlopen
xterm
pef@darkstar:/Users/pef $ curl -sH 'Accept: url = 'http://api.icndb.com/jokes/random?li
application/json' mitTo=[nerdy]'
http://api.icndb.com/jokes/random | python3 -m response = urlopen(url)
json.tool data = response.read()
{ values = json.loads(data)
"type": "success",
"value": {
print (values['value']['joke'])
"categories": [
"nerdy"
], Le format JSON
"id": 543,
"joke": "Chuck Norris's programs can Le format JSON est un format très utile pour utiliser des
pass the Turing Test by staring at the
interrogator." APIs de services Web et le développement de 𝜇services
} basés sur l’architecture REST.
}
Cette architecture REST peut être définie par les 5 règles
"tx_index": 1939114,
"ver": 1, suivantes :
"vin_sz": 3, 1. l’URI comme identifiant des ressources (URL expli-
"vout_sz": 2,
"weight": 2468 cite).
} 2. les verbes HTTP comme identifiant des opérations (GET,
],
"ver": 1 POST, PUT DELETE).
} 3. les réponses HTTP comme représentation des res-
Mon’tit Python – P-F.B.
sources (JSON).
4. les liens comme relation entre ressources (définition
de l’attribut «rel» en accord avec l’IANA).
5. un paramètre comme jeton d’authentification,
COMPLÉMENT
if os.path.exists("chemin_fichier"):
# l'entrée existe
print('fichier existe')
if os.path.isfile("chemin_fichier"):
# c'est un fichier
print("c'est un fichier et non un répertoire")
if os.path.isdir("chemin_fichier") :
# c'est un répertoire
print("c'est un répertoire et non un fichier")
Mon’tit Python – P-F.B.
ma_socket = socket.socket(socket.AF_INET,socket.SOCK_DGRAM)
mcast = struct.pack('4sl', socket.inet_aton('224.0.0.127'), socket.INADDR_ANY)
ma_socket.setsockopt(socket.IPPROTO_IP, socket.IP_ADD_MEMBERSHIP, mcast)
mon_nom_symbolique = subprocess.run(['uname','-a'],stdout=subprocess.PIPE).stdout.split()[1]
mon_adresse_ip = socket.gethostbyname(socket.gethostname(mon_nom_symbolique))
Scapy
Le module scapy dispose de capacités à traiter le contenu des paquets reçus suivant le protocole associé.
Cette bibliothèque d’injection de paquets forgés dispose de fonctions d’analyse et d’affichage de données de différents
protocoles : DNS(), IP(), UDP(), etc.
Mon’tit Python – P-F.B.
⋄ lors de la demande d’aide avec «-h», chaque option dispose d’une description :
xterm
$ ./ma_commande.py -h
Usage: ma_commande.py [options]
Options:
-h, --help show this help message and exit
-l NOM_FICHIER, --lire-fichier=NOM_FICHIER
lit un fichier
-c, --convertir convertit le fichier
⋆ à un booléen :
xterm
Mon’tit Python – P-F.B.
$ ./ma_commande.py -c
À l’exécution :
xterm
Mon’tit Python – P-F.B.
$ ./ma_commande.py -l mon_fichier.txt -c
{'nom_fichier': 'mon_fichier.txt', 'conversion': True}
28 Débogage : utilisation du mode interactif 93
Le mode interactif pour «dialoguer» avec le programme
On peut déclencher l’exécution d’un programme Python, puis basculer en mode interactif dans le contexte de
ce programme, avec l’option «-i» :
xterm
$ python3 -i mon_programme.py
Il est alors possible de consulter la valeur des variables ou d’appeler des fonctions etc.
⊳ avec en plus la complétion des variables et méthodes :
Mon’tit Python – P-F.B.
#!/usr/bin/python3
import code,readline,rlcompleter
...
vars = locals()
readline.set_completer(rlcompleter.Completer(vars).complete)
readline.parse_and_bind("tab: complete")
code.interact(local=vars)
COMPLÉMENT
6 print (compteur)
[EOF]
(Pdb) n
> /home/pef/PYTHON3/tester_dbg.py(5)<module>()
-> compteur += 1
(Pdb) compteur
2
COMPLÉMENT
Surveiller l’exécution, la «journalisation» : le module logging 95
parser = optparse.OptionParser()
parser.add_option('-l', '--logging', dest='logging', default=False, action='store_true')
parser.add_option('-f', '--logging-file', dest='logging-file',help='Logging file name')
if dico_options['logging'] :
logging.basicConfig(level=logging.DEBUG, filename=dico_options['logging-file'],
format='%(asctime)s %(levelname)s: %(message)s',
datefmt='%Y-%m-%d %H:%M:%S')
À l’exécution :
xterm
Mon’tit Python – P-F.B.
$ python debogage.py -l
2018-08-13 14:57:05 DEBUG: Ceci est un message de debogage
29 Index 97
a d lecture 56–57
accents 21, 24 débogage ouverture 54
aide 9 debogueur 94 taille 88
aléatoire 68 interactif 93 fonction 65–66
logging 95–96 format 29
c dictionnaire 40
caractère 17 combinaison de listes 42 i
chaîne 38 tri 41 itération
chaîne UTF-8/octets 23, 49 données structurées 58 for 33
chaîne&format 29 chaîne de format 59 for octets 39
chaîne&liste 38 for(;;) 33
codage&rang 18 e rupture 15
opération sur chaîne 28 entrée/sortie while 15
commentaire 11 input 46
condition 14 print 45 l
assert 67 espace de nom 43 liste 30
expression logique 16 exécuter construction avancée 35
contrôle d’erreur commande 70 file 32
assert 67 processus (fork) 71–72 pile 32
exception programme 10 tableau 37
raise 53 expression régulière 60 logging 95
try 52 motif 61
conversion split 64 m
Mon’tit Python – P-F.B.