Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à...

96
Formation Python 3 Release 2015.12 NormandDEV December 04, 2015

Transcript of Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à...

Page 1: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3Release 2015.12

NormandDEV

December 04, 2015

Page 2: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants
Page 3: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

CONTENTS

1 Sommaire 31.1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31.2 Les fonctions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241.3 Les modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 341.4 Programmation objet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 441.5 Les tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 721.6 Projet BallPack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 851.7 Documentations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91

i

Page 4: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

ii

Page 5: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par desintervenants locaux.

6 demi-journées:

• Introduction : installation et prise en main, initiation à la syntaxe Python, les types de données standard, lesstructures de contrôle.

• Les fonctions

• Les modules et le packaging

• La programmation objet

• Les tests et la documentation

• Projet de manipulation

Les travaux pratiques de la formation seront effectués avec l’environnement virtualenv et IPython (Python 3).

Les supports de cours sont disponibles sur Sourcesup:

https://sourcesup.renater.fr/frs/?group_id=2055

CONTENTS 1

Page 6: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

2 CONTENTS

Page 7: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

CHAPTER

ONE

SOMMAIRE

1.1 Introduction

1.1.1 Qu’est ce que Python ?

Python a été créé par Guido van Rossum en 1989.

Le langage Python :

• est placé sous une licence libre proche de la licence BSD2

• fonctionne sur la plupart des plates-formes informatiques, des supercalculateurs aux ordinateurs centraux,de Windows à Unix en passant par GNU/Linux, Mac OS, ou encore Android, iOS, et aussi avec Java ou encore.NET.

Il est conçu pour optimiser la productivité des programmeurs en offrant des outils de haut niveau et une syntaxe simpleà utiliser.

Que peut-on faire avec Python ?

Web

Django, TurboGears, Zope, Plone, ...

Bases de données

MySQL, PostgrSQL, Oracle, ...

Réseaux

3

Page 8: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

TwistedMatrix, PyRO, ...

UI

Gtk, Qt, Tcl/Tk, WxWidgets, Kivy,...

Représentation graphique

gnuplot, matplotlib, VTK, ...

Calcul scientifique

numpy, scipy, sage, ...

...

Principales caractéristiques de ce langage

Python est un langage de programmation qui permet de travailler plus vite.

• langage de programmation à usage général de haut niveau

• riche et polyvalent

• interprété

• ouvert et multiplateforme

• facilité d’apprentissage et de mise en œuvre

• diversité des outils de développement

• stable/mature, très répandu et évolutif

Comment est traduit mon code en langage machine ?

Il existe 2 techniques principales pour effectuer la traduction en langage machine de mon code source :

• Interprétation

• Compilation

4 Chapter 1. Sommaire

Page 9: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Comment est traduit mon code en langage machine ?

Qu’en est-il pour mon code Python ?

Les différentes versions de Python

Il existe deux versions de Python (Python 2.x et Python 3.x).

Les modifications apportées sont assez importantes pour qu’un code écrit en 2.x ne fonctionne pas en 3.x. Pour vousaider à transférer vos codes, vous avez à disposition un programme 2to3.py.

Nous avons choisi de réaliser cette formation sur la version 3 et en utilisant l’environnement virtualenv. Le choix dela version est important puisqu’il est en étroite relation avec les modules et paquets dont vous avez besoin.

Les implémentations de Python

Il existe plusieurs implémentations de Python qui permettent d’étendre le langage avec des librairies dans d’autreslangages :

• CPython : L’interpréteur de référence de Python. Il génère du byte-code Python (fichier *.pyc) et est écrit enC; il permet d’étendre le langage avec des librairies C.

• Jython : Interpréteur qui permet de coupler du Python et du Java dans le même programme, génère du byte-codeJava.

• IronPython : Implémentation de Python qui vise .Net et Mono, permet de coupler Python avec le framework.Net.

• Pypy : Implémentation de Python en Python; projet de recherche pour obtenir une implémentation plus rapideque l’implémentation de référence (CPython).

Plus d’informations sur les implémentations ici

Les différents IDE pour Python

IDE multi-plateformeNetBeans PyCharmKDevelop PyDevWing IDE - propriétaire SpyderIDLE IDLEXIEP PTKPyStudio Eric IDE

Plus d’informations sur les IDE ici

1.1. Introduction 5

Page 10: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

1.1.2 L’environnement virtualenv

Description

Virtualenv est un outil qui permet de créer des environnements Python isolés. Cela permet de travailler sur plusieursprojets ayant chacun ses propres dépendances en évitant notamment les conflits entre différentes versions d’une mêmebibliothèque.

Utilisation

• pour créer un environnement virtuel (virtualenv) nommé env : pyvenv-3.4 env

• pour rentrer dans le virtualenv : source env/bin/activate

• pour installer ipython dans le virtualenv: pip install ipython

• pour en sortir : deactivate

• pour le supprimer : rm -rf env

Premiers pas avec l’interpréteur interactif

Ce matin, le cours va se poursuivre sous IPython.

IPython est un interpréteur Python à la différence qu’il permet de :

• chercher une méthode dans un module ou un namespace,

• afficher le prototype d’une méthode ou d’une fonction,

• utiliser la complétion dans l’espace de nom local et

• afficher l’historique des commandes.

Dans IPython, on accède à l’aide en tapant help() et on quitte l’aide avec la commande quit.

L’aide dans IPython, c’est aussi :

• help(“topics”) : énumère les différents “concepts” Python au sujet desquels on peut demander de l’aide ; taperensuite

• help(“SUJET”) pour avoir de l’aide sur le SUJET souhaité

• help(objet) : affiche des informations sur l’objet Python spécifié (variable, fonction...) telles que son type, sesméthodes...

• help(“module”) : affiche l’aide relative au module spécifié ; si le module est importé on peut directement fairehelp(module) (sans guillemets)

• help(“module.objet”) : affiche directement l’aide relative à l’objet spécifié du module

Pour vous donner une idée taper :

help("print")print("Hello World !")1+1

6 Chapter 1. Sommaire

Page 11: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

1.1.3 Initiation à la syntaxe de Python

Le nom des variables en Python doit satisfaire plusieurs critères :

• il ne doit pas commencer par un chiffre,

• les minuscules et les majuscules sont distinguées,

• il ne doit pas y avoir de caractères accentués.

Le dernier critère n’est plus à vérifier dans la version 3.x puisqu’il travaille en Unicode.

Le langage Python est basé sur un certain nombre de documents proposant des améliorations du langage: les PEPs.

Le guide des bonnes pratiques concernant l’écriture de code Python est défini dans le PEP8.

Python est sensible aux noms des variables. Il n’aime pas les accents (théoriquement plus avec Python 3 puisqu’iltravaille en Unicode) mais différencie les minuscules des majuscules. Nous resterons en ASCII pour éviter tout litige.

Comme tout langage, Python a ses mots clés :

help("keywords")False def if raiseNone del import returnTrue elif in tryand else is whileas except lambda withassert finally nonlocal yieldbreak for notclass from orcontinue global pass

Nous allons maintenant voir les types simples et les types containers.

Les types simples

4 types simples:

• booléen,

• entier,

• réel,

• complexe.

Les booléens

# le type booléen prend les valeurs True ou Falselogique = Truelogique = Falsetype(logique)

Les entiers

a = 2 ; i = -12# int : entier de précision illimitée !v = 2**80 # => 1208925819614629174706176

1.1. Introduction 7

Page 12: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

# définition d'entiers en binaire, octal ou hexadéc.:k = 0b111 # => 7m = 0o77 # => 63n = 0xff # => 255# conv. chaînes bin/octal/hexa en entier & vice-versa:int('111', 2) # => 7, et inverse: bin(7) => '0b111'int('77', 8) # => 63, et inverse: oct(63) => '0o77'int('ff', 16) # => 255, et inverse: hex(255) => '0xff'

Quelques remarques

• ; n’est utilisé que si il y a plusieurs instructions sur la même ligne.

• La fonction type() vous permet de connaître le type de la variable.

• Le symbole # permet d’écrire un commentaire jusqu’au retour à la ligne.

Les réels

Les réels sont codés en double précision (64 bits).

b = -3.3 ; r = 3e10abs(b) # => 3.3# arrondi et conversionint(3.67) # => 3 (int)int(-3.67) # => -4 (int)round(3.67) # => 4 (int), comme round(3.67, 0)round(3.67,1) # => 3.7 (float)round(133,-1) # => 130 (int)round(133,-2) # => 100 (int)

Complexe flottant

cplx = 3.4 + 2.1j # ou: cplx = complex(3.4, 2.1)cplx.real # => 3.4cplx.imag # => 2.1

Remarque : Python est un langage objet. Vous verrez qu’il existe des méthodes associés à un type comme ici pour lesnombres complexes.

Interaction avec l’écran et le clavier

Deux fonctions vont nous être utiles : print et input.

- print(arguments)- input(prompt)

Attention, si vous souhaitez entrer une chaîne de caractères, il vous faudra utiliser les guillemets (simples ou doubles).

help("print")help("input")

a = 3b = 2print('Le produit de', a, 'et', b, 'est', a*b)

8 Chapter 1. Sommaire

Page 13: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

print('Le produit de %d et %e est %e'%(a, b, a*b))print('Le produit de {0} et {1:.3f} est {2:.3f}'.format(a, b, a*b))

nom = input("Quel est votre nom ?")

age = input("Quel âge avez-vous ?")

type(age)

age = int(age)print (bin(age))print (hex(age))

Instruction sur plusieurs lignes et commentaires

Imaginons que nous sommes des linguistes ; on veut étudier la première phrase de présentation du CNRS :

“Le Centre national de la recherche scientifique est un organisme public de recherche (Établissement public à caractèrescientifique et technologique, placé sous la tutelle du Ministère de l’Éducation nationale, de l’Enseignement supérieuret de la Recherche). Il produit du savoir et met ce savoir au service de la société.”

• Faites afficher cette phrase : print(“blabla”)

print("Le Centre national de la recherche scientifique est un organisme public de recherche (Établissement public à caractère scientifique et technologique, placé sous la tutelle du Ministère de l'Éducation nationale, de l'Enseignement supérieur et de la Recherche).")

Pour des raisons de libilité et de portabilité, le guide de style Python recommande de ne pas dépasser 79 caractères surune ligne de code...

print("Le Centre national de la recherche scientifique est un organisme public de recherche ""(Établissement public à caractère scientifique et technologique, placé sous la ""tutelle du Ministère de l'Éducation nationale, de l'Enseignement supérieur et de la ""Recherche)")

Essayer en utilisant des apostrophes à la place des guillemets...

print('pourtant ca marche avec ces apostrophes')

Vous avez des apostrophes dans votre chaîne de caractères, utilisez les guillemets :

print("Puisqu'il pleut, jusqu'à demain, c'est...")

Pour les commentaires sur plusieurs lignes, vous pouvez utiliser le triple guillemet ou le triple apostrophe...

"""ceci est un commentaire surplusieurs lignes"""'''ceci est un autre commentaire surplusieurs lignes'''# Rappel : celui-ci n'est valable que jusqu'à la fin de la ligne

a = ( 3+ 4)

print(a)

1.1. Introduction 9

Page 14: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Assignation simple et multiple

L’assignation se fait avec le signe =.

# Que valent a et b ?a = 2; b = 3a,b = 2,3print(a,b)a = b = 4print(a,b)a,b = b,a

On reviendra sur les tuples mais voici un exemple :

tuple1 = (1,'python')x,y = tuple1# Que valent x et y ?print(x, y)print(type(x))type(y)

Référencement

x = 'python' # création de la donnée "python" référencé par "x"print (type(x)) # l'OBJET référencé est de type "str"print (id(x)) # adresse mémoirey = x # nouvelle variable pointant sur la même donnéeprint (id(y)) # même adresse mémoireprint (x)print (y)x = 123 # création de la donnée "123" et changement de référencement pour "x"print (type(x)) # l'OBJET référencé est de type "int"print (id(x)) # x pointe vers une autre adresse mémoireprint (y)del(y) # on supprime le référencement de y sur la donnée "python"

# le garbage collector supprimera la donnée automatiquement# libérant ainsi de la mémoire...

Opérateurs de base

Les opérateurs mathématiques de base sont :

• les classiques : ** + - / * **

• la division entière tronquée : //

• la puissance : **

• le modulo : %

print (3+2)print (3-2)print (3*2)

print (3/2)print (3/2.)print (3//2)

10 Chapter 1. Sommaire

Page 15: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

print (10**2)print (3%2)

On pourra noter que la fonction divmod(a,b) renvoie le tuple (a//b,a%b).

divmod(7,3)

Les opérateurs + et ** * ** s’appliquent aussi aux séquences (chaînes, listes, tuples).

2*'a tchick ' + 3*'aie '

Les opérateurs pré- et post-incrémentation ++ et – n’existent pas en Python. On utilisera à la place le +=1 et le -=1.

x = 10 # x vaut 10x += 1 # x = x + 1 : x = 11x -= 1 # x = x - 1 : x = 10x *= 5 # x = x * 5 : x = 50x /= 10 # x = x / 10 : x = 5x %= 2 # x = x % 2 : 1print(x)

fruit = 'pomme' # renvoie "pomme"fruit +='s' # renvoie "pommes"print(fruit)

monTuple = (1,2,3) # monTuple vaut (1,2,3)print (monTuple)monTuple += (4,) # monTuple = monTuple + (4,) : monTuple = (1,2,3,4)print (monTuple)monTuple *= 2 # monTuple = monTuple * 2 : monTuple = (1,2,3,4,1,2,3,4)print (monTuple)

Opérateurs de comparaison, d’objets et logiques

Ces opérateurs renvoient les valeurs logiques True ou False qui sont de type booléen.

• Opérateurs de comparaison

opérateur== égal!= différent< inférieur<= inférieur ou égal> supérieur>= supérieur ou égal

• Opérateurs d’objets

opérateuris même objetin membre du container

• Opérateurs logiques

opérateurnot négation logiqueand ET logiqueor OU logique

1.1. Introduction 11

Page 16: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

a, b = 1, 2a < b

["a",1,"b"] == [1,2,3]

a, b = [1,2], [1,2]a is b

a = b = [1,2]a is b

2 in [1,2,3]

En Python, on peut chaîner les comparaisons :

a = 12print(10 < a < 20)print(a > 10 and a < 20)

1.1.4 Les types de données (containers)

Contrairement aux types simples, les types containers permettent d’instancier des objets contenant plusieurs données.

On distingue trois catégories de containers implémentés sous formes de 6 types de base :

• les séquences : chaîne, liste, tuple

• les maps ou hashs : dictionnaire

• les ensembles : set, frozenset

Les séquences : chaînes de caractères

Les chaînes de caractères se délimitent par des apostrophes ou des guillemets.

maChaine1 = "tout est bon dans le Python"maChaine2 = 'tout est bon dans le Python'

maChaine3 = 'C\'est comme ça'maChaine4 = "C'est comme ça" #pour la gestion des apostrophes dans les chainesmaChaine4[4]

Les chaînes de caractères en Python sont immutables. Les chaînes ne sont pas modifiables dans le sens où toutesmodifications entraînent la création de nouvelles chaînes. Le garbage collector effacera alors automatique la ou leschaînes non référencées.

12 Chapter 1. Sommaire

Page 17: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Une chaîne de caractères est une séquence ordonnée de caractères ce qui permet de s’y référer par l’utilisationd’indices.

print ("bonjour"[0:3])print ("bonjour"[-4:])

• concaténation

chain1 = "Tout est bon "chain2 = "Python"chain = chain1 + "dans le " + chain2print (chain)print ("2.0" + "re")3 * "po"

Il existe différentes méthodes associées aux chaînes comme par exemple :

• len(chain) : renvoie la taille d’une chaîne,

• chain.find : recherche une sous-chaîne dans la chaîne,

• chain.rstrip : enlève les espaces de fin,

• chain.replace : remplace une chaîne par une autre,

• chain.split : découpe une chaîne,

• chain.isdigit : renvoie True si la chaîne contient que des nombres, False sinon...

• ...

Pour en savoir plus, je vous invite à taper : help(str)

len(chain)

chain.split(" ")

1.1. Introduction 13

Page 18: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Les séquences : les listes

Une liste dans Python permet de stocker une collection ordonnée sous forme de séquence. La modification des élé-ments est dynamique et les éléments peuvent être hétérogènes (de n’importe quel type).

maListe = [1, 2.3, "ab", 3.4 + 2.1j, [0, 1, 2]]maListe

[1, 2.3, 'ab', (3.4+2.1j), [0, 1, 2]]

maListe[4][1]

1

print(type(maListe))print(type(maListe[3]))

<class 'list'><class 'complex'>

• Modification

Lis = maListeprint (Lis)maListe[2] = 6maListe[4][1] = 3print (maListe)print (Lis)

• Concaténation

l = [0] * 10l

• Copie de listes

Si l’on souhaite dupliquer les données d’une liste, il faut comprendre qu’en Python, une simple assignationmaListeBis=maListe n’effectue pas une copie des données. Les variables maListeBis et maListe référencentla même liste !

Pour recopier correctement une liste :

– maListeBis=maListe[:] duplique seulement les éléments de premier niveau. Les listes et/ou dictionnairesimbriqués continueront en revanche d’être référencés et non dupliqués.

14 Chapter 1. Sommaire

Page 19: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

– maListeBis=copy.deepcopy(maListe) permet une copie complète récursive. Il faudra néanmoins importerle module copy.

Plusieurs méthodes peuvent être appliquées aux listes.

maListe = [1,2.3,"ab",3.4 + 2.1j,[0,1,2]]# Que permettent ces méthodes :len(maListe) # longueur de la listemaListe.sort() # trie la liste (ici, ce n'est pas possible: les éléments ne sont pas comparables)maListe.append(5) # ajoute un élement à la finmaListe.insert(0,'a') # ajoute l'élément 'a' en position 0 dans la listemaListe.extend(['a','b']) # ajoute les éléments 'a' et 'b' à la liste (concaténation de listes)maListe.reverse() # inverse l'ordre des élémentsmaListe.index(5) # première position à laquelle apparaît la valeur 5 dans la listemaListe.remove(5) # supprime la première occurrence de la valeur 5 dans la listemaListe.pop() # supprime et renvoie le dernier élément de la liste

Pour plus d’aide, je vous invite à regarder l’aide : help(list)

Les séquences : les tuples

Le tuple Python est l’implémentation de la liste mais en lecture seule. Le tuple Python est donc une collection ordonnéenon modifiable d’éléments hétérogènes. On retrouvera ainsi les mêmes méthodes que pour les listes sans cellesconcernant les modifications.

• L’intérêt des tuples par rapport aux listes est qu’ils occupent moins d’espace mémoire et que leur traitement estplus efficace.

monTuple = 'a','b','c','d'monTuple[0]

monTuple[0] = 'alpha'

monTuple = ('alpha',) + monTuple[1:]monTuple

Si le premier niveau des tuples n’est pas modifiable, on peut en revanche modifier les objets modifiables imbriqués.

monTuple2 = (1, 2, [3, 4], 6)monTuple2[2][0] = 1monTuple2

On peut convertir un tuple en liste avec la fonction list()

print (monTuple2)liste2 = list(monTuple2)print (liste2)type(liste2)

On peut également concaténer deux tuples :

monTuple + monTuple2

Pour plus d’aide, je vous invite à regarder l’aide : help(tuple)

Les maps ou hash : dictionnaire

Un dictionnaire est une liste modifiable d’éléments hétérogènes mais indicés par des clés.

1.1. Introduction 15

Page 20: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

• Un dictionnaire n’est pas une séquence.

• Un dictionnaire est constitué de clés et de valeurs.

• On ne peut pas concaténer un dictionnaire avec un autre.

dic = {'a': 1, 'b': 2}dic

dic2 = {}dic2['a'] = 1dic2['b'] = 2dic2

dic3 = dict(a=1, b=2)dic3

dic4 = dict(zip(('a','b'), (1,2)))dic4

• Pour récupérer une valeur :

dic['a']dic.get('a')

• Ajouter un élément, modifier une valeur, supprimer un élément :

dic[1] = 7 # Ajoute un élément (clé, valeur)dic['b'] = 3 # On modifie la valeur "2" par "3"del(dic['b']) # On supprime l'élément dont la clé est 'b'

# A vous de découvrir ce qui se passe pour ceci :val = dic.pop('b')

• Ajouter plusieurs éléments, fusion de dictionnaire :

dicBis = {'c':3,'d':4}dic.update(dicBis)dic

• Pour copier un dictionnaire, utiliser un nouveau référencement ne suffit pas, il faut utiliser la méthode copy.

# copier le dictionnaire dic dans le dictionnaire copieDeDic# quelle fonction vous permet de vous assurer de la bonne copie ?

Plusieurs méthodes existent pour les dictionnaires :

len(dic) #taille du dictionnairedic.keys() #renvoie les clés du dictionnaire sous forme de listedic.values() #renvoie les valeurs du dictionnaire sous forme de listedic.has_key(cle) #renvoie True si la clé existe, False sinondic.get(cle) #donne la valeur de la clé si elle existe

Remarque : Les méthodes .keys(), .values() et .items() retournent des objets permettant d’itérer, par une boucle for,respectivement les clés, les valeurs et les paires clés/valeurs.

Pour plus d’aide : help(dic)

16 Chapter 1. Sommaire

Page 21: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Les ensembles : set

Ce type permet de créer des collections de données non ordonnées modifiables constituées d’éléments uniques detype immutable.

Le type set n’est donc pas une séquence ; en revanche, il supporte l’itération. C’est comme un dictionnaire avec desclés sans valeurs.

monSet = {1,2,3,1,4}monSet # éléments uniques

monSet1 = set((1,2,1,4,3))monSet1

Regardez ce que renvoie la commande type. De quelle longueur est ce set ?

• Ajout d’éléments

monSet = {1,2,3,1,4}monSet

monSet |= {5,6}monSet

monSet = monSet|{7,8}monSet

monSet.update({9,10})monSet

monSet.add(11)monSet

• D’autres méthodes

monSet.remove(3) # détruit l'élément "3"monSet.discard(3) # détruit l'élément "3" sans générer d'erreur si l'élément est absentmonSet.pop() # retourne un élément arbitraire et le détruitmonSet.clear() # détruit tous les éléments

• Opérations propres aux ensembles

monSet | monSet1 # union => {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}monSet & monSet1 # intersection => {1, 2, 3, 4}monSet - monSet1 # différence => {5, 6, 7, 8, 9, 10, 11}monSet1 - monSet # différence => set()monSet ^ monSet1 # ou exclusif => {5, 6, 7, 8, 9, 10, 11}

• Tests

{'a','b'} == {'b','a'} # sets identiques => True'a' in {'a','b','c'} # présence d'un élément isolé => True{'a','b'} <= {'a','b','c','d'} # présence de tous les éléments => True

• Copie d’un set

Comme pour les listes et les dictionnaires, on en peut pas copier en faisant un simple tonSet=monSet. Il faututiliser :

tonSet = monSet.copy()

Pour plus d’aide : help(set)

1.1. Introduction 17

Page 22: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Les ensembles : frozenset

Un type frozenset est un set mais immutable (non-modifiable). Tout ce qui s’applique aux sets, s’appliquent égalementau frozenset à l’exception de tout ce qui concerne les modifications.

monFrozenset = frozenset({'x','y','z','x'}) # ou bienmonFrozenset = frozenset(('x','y','z','x'))

Pour plus d’aide : help(frozenset)

Récapitulatif sur les différents types de données

• Simple

– modifiable

* aucun

– immutable

* booléen

* entier

* entier flottant

* complexe

• Container

– modifiable

* liste (séquence)

* set (ensemble)

* dictionnaire (map)

– immutable

* tuple (séquence)

* frozenset (ensemble)

* chaîne (séquence)

1.1.5 Les structures de contrôle

En Python, les structures de contrôle existent par l’indentation des blocs de code. L’indentation est donc très impor-tante en Python. Cette indentation apporte au langage une lisibilité et légerté au code (absence d’accolades, points-virgules,...)

18 Chapter 1. Sommaire

Page 23: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Le guide de style Python mentionne qu’il est préférable d’utiliser les espaces plutôt que la tabulation. Il indique même4 espaces par niveau d’indentation.

Exécution conditionnelle IF - ELIF - ELSE

La forme de cette structure de contrôle est montrée ci-dessous. Les parties elif et else sont bien sûr facultatives.

a = 10.if a > 0:

print ("a est strictement positif")if a >= 10:

print ("a est un nombre")else:

print ("a est un chiffre")a += 1

elif a is not 0:print ("a est strictement negatif")

else:print ("a est nul")

print (a)

Comme dans d’autres langages, Python offre l’écriture d’expressions conditionnelles :

a = 10print ("a est positif" if a>=0 else "a est négatif")

if a >= 0:print ("a est positif")

else:print ("a est négatif")

1.1. Introduction 19

Page 24: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Boucle WHILE

La boucle while permet d’exécuter un bloc d’instruction aussi longtemps qu’une condition (expression logique) estvraie.

while <test1>:<blocs d’instructions 1>if <test2>:

breakif <test3>:

continueelse:

<blocs d’instructions 2>

• break : sort de la boucle sans passer par else

• continue : remonte au début de la boucle

• pass : ne fait rien

• else : lancé si et seulement si la boucle se termine normalement

nb = 1 ; stop = 3# Affiche le carré des nombres de nb à stopwhile nb <= stop:

print(nb, nb**2)nb += 1

Boucle FOR

La boucle for permet d’itérer les valeurs d’une liste, d’un tuple, d’une chaîne ou de tout objet itérable. Comme dansles autres structures de contrôle, le caractère : (double point) définit le début du bloc d’instruction contrôlé par for.

for <cible> in <objet>:<blocs d’instructions>if <test1>:

breakif <test2>:

continueelse:

<blocs d’instructions>

sum = 0for i in [1, 2, 3, 4]:

sum += isum

L = [ x + 10 for x in range(10)]L

• Sur une liste ou un tuple :

maList = [1,2,3]for n in maList:

print (n)

Pour itérer sur une suite de nombres entiers, on utilise souvent la fonction range :

20 Chapter 1. Sommaire

Page 25: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

for index in range(len(maList)):print(index, maList[index])

Vous pouvez également utiliser la fonction enumerate qui retourne un objet grâce auquel vous pouvez itérer sur lesindices et les valeurs d’une séquence.

for index,val in enumerate(maList):print(index, val)

• Sur une chaîne :

voyelles = 'aeiouy'for car in 'chaine de caracteres':

if car in voyelles:print (car)

• Sur un dictionnaire :

carres = {}for n in range(1,4):

carres[n] = n**2print (carres)

for k in carres: # itère par défaut sur la clé !# identique à: for k in carres.keys():print (k)

MAP et ZIP

• map applique une méthode sur une ou plusieurs séquences.

• zip permet de parcourir plusieurs séquences en parallèle.

Remarque : map peut être beaucoup plus rapide que l’utilisation de for.

S = '0123456789'M = map(int, S)for x in M:

print(x)

L1 = [1, 2, 3]L2 = [4, 5, 6]for (x, y) in zip(L1, L2):

print (x, y, '--', x + y)

1.1.6 Exercices

Exercice 1

Je vous propose de progresser vers l’utilisation de l’éditeur de fichier. Nous allons donc utiliser la fenêtre de gauche.

Écrivez un programme qui convertisse en degrés Celsius une température exprimée au départ en degrés Fahrenheit, oul’inverse.

• La formule de conversion est : TF = TC ×1,8+32

• TF : température en degré Fahrenheit

1.1. Introduction 21

Page 26: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

• TC : température en degré Celsius

Solution

Une solution non optimale mais du niveau des notions vues dans cette première partie du cours...

"""Created on Wed Nov 26 22:31:38 2014

Écrivez un programme qui convertisse en degrés Celsius une températureexprimée au départ en degrés Fahrenheit, ou l’inverse.

La formule de conversion est : TF = TC × 1,8 + 32TF : température en degré FahrenheitTC : température en degré Celsius

@author: chalgand"""goodAnswer = Falsewhile goodAnswer == False:

print("Dans quel sens voulez-vous faire la conversion ?")print("1 - Degré Celsius vers Degré Fahrenheit")print("2 - Degré Fahrenheit vers Degré Celsius")answer = input("Choisissez le sens : ")if answer == "1" or answer == "2":

goodAnswer = Trueprint(answer)

if answer == "1":text = "Degré Celsius vers Degré Fahrenheit"

else:text = "Degré Fahrenheit vers Degré Celsius"

print("Vous avez choisi la conversion : " + text)

temp = "une mauvaise température"while type(temp) != int:

temp = int(input("Veuillez entrer la température à convertir: "))

if answer == "1":print(temp, " degré(s) Celsius = ", temp*1.8+32,

" degré(s) Fahrenheit")else:

print(temp, " degré(s) Fahrenheit = ", (temp-32)/1.8," degré(s) Celsius")

Exercice 2

Écrivez un code Python qui affiche une suite de 12 nombres dont chaque terme est égal au triple du précédent.

Exercice 3

Écrivez un code Python qui affiche

***

22 Chapter 1. Sommaire

Page 27: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

************

Exercice 4

Que fait le code suivant ?

ch = 'une chaine'i = ch[4]print(i)j = ch(4)print(j)

Exercice 5

Soient les listes suivantes :

t1 = [31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]t2 = ['Janvier', 'Février', 'Mars', 'Avril', 'Mai', 'Juin',

'Juillet', 'Août', 'Septembre', 'Octobre', 'Novembre', 'Décembre']

Écrivez un code Python qui insère dans la seconde liste tous les éléments de la première, de telle sorte que chaque nomde mois soit suivi du nombre de jours correspondant :

['Janvier',31,'Février',28,'Mars',31, etc...].

Exercice 6

Soit le dictionnaire suivant :

dico1 = {'computer': 'ordinateur', 'mouse': 'souris','printer': 'imprimante', 'keyboard': 'clavier'}

Écrivez un code Python qui inverse les clés et les valeurs permettant de passer d’un dictionnaire anglais/français à undictionnaire français/anglais.

Exercice 7

Soit la chaîne de caractères suivante :

chaine = 'Ceci est une chaine.'

• Est-ce que chaine est un objet? Quelles sont ses méthodes?

• Mettez dans une variable CHAINE cette chaîne en majuscules.

• Mettez dans une variable nb_mot le nombre de mots de la phrase.

• Comptez le nombre d’occurrences de chaque lettre (on utilisera un dictionnaire et la fonction get).

1.1. Introduction 23

Page 28: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

1.2 Les fonctions

1.2.1 Définition

Une fonction représente un traitement dédié à une tâche particulière:

• quand on appelle une fonction, on quitte le programme principal pour aller dans la fonction

• on revient dans le programme principal à la fin de la fonction

Idéalement, une fonction ne doit pas dépasser 20 à 30 lignes.

# définitiondef ma_fonction():

"""Cette fonction ne fait rien et ne produit aucun résultat"""pass

# Appel de la fonctionma_fonction()

# Appel et affichage du résultatprint(ma_fonction())

Résultat

None

Avec paramètres:

def ma_fonction(a, b):"""Cette fonction ne fait rien et ne produit aucun résultat"""pass

Une fonction contient:

• le mot clef def

• un nom

• (

• des paramètres

• ):

• le corps de la fonction

L’exécution d’une fonction se termine lorsque l’on termine le block indenté ou au premier return.

1.2.2 Nom des fonctions

Des conventions de nommage et de codage sont définies dans la PEP 8 (site en anglais). C’est d’ailleurs possible demettre en forme automatiquement vos programmes python en utilisant autopep8.

autopep8 --in-place --aggressive --aggressive moche.py

En bref, il est recommandé d’utiliser que des minuscules avec les mots séparés par un souligné (_).

Des bons exemples:

• calcul()

24 Chapter 1. Sommaire

Page 29: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

• mon_travail()

D’autres à éviter:

• Affiche()

• GetName()

1.2.3 Corps de la fonction

Modification du corps de la fonction.

def ma_fonction():print("Dans ma fonction")

# Appel à ma_fonctionma_fonction()

Resultat:

Dans ma fonction

# Appel et affichage du résultatprint(ma_fonction())

Dans ma fonctionNone

1.2.4 Retour de données

def ma_fonction():print("Dans ma fonction")returnprint("Toujours dans ma fonction")

print(ma_fonction())

Résultat:

Dans ma fonctionNone

def ma_fonction(a, b):resultat = int(a*b)print(a, "x", b, "=>", resultat)return resultat

val = ma_fonction(10, 4.2)print("Le résultat de ma_fonction(10, 4.2) est:", val)

10 x 4.2 => 42Le résultat de ma_fonction(10, 4.2) est: 42

1.2. Les fonctions 25

Page 30: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

1.2.5 Passage de paramètres

def ma_fonction(a, b):print("coucou", a, "et", b)

ma_fonction("tata", "toto")

Résultat

coucou tata et totoNone

Python passe les variables par adresse.

def ma_fonction(a, b):print("{0} => 5, \"{1}\" => \"tata\"".format(a[0], "".join(b)))a[0] = 5b[1] = "a"b[3] = "a"

a = [10]b = list("toto")ma_fonction(a, b)print("a=", a[0], ",", "b=", "".join(b))

10 => 5, "toto" => "tata"a= 5 , b= tata

Cependant, les types scalaires de Python entier, flottant et chaine sont immuables.

def ma_fonction(a, b):print("{0} => 5, \"{1}\" => \"tata\"".format(a, b))a = 5b = "tata"

a = 10b = "toto"ma_fonction(a, b)print("a=", a, ",", "b=", b)

10 => 5, "toto" => "tata"a= 10 , b= toto

Pour communiquer les changements locaux à la fonction dans le programme appelant, il faut les retourner à l’aide dereturn.

def ma_fonction(a, b):print("{0} => 5, \"{1}\" => \"tata\"".format(a, b))a = 5b = "tata"return(a, b)

a = 10b = "toto"a, b = ma_fonction(a, b)print("a=", a, ",", "b=", b)

10 => 5, "toto" => "tata"a= 5 , b= tata

26 Chapter 1. Sommaire

Page 31: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Paramètres nommés

Pour plus de lisibilité ou parce que ça vous dit, il est possible de nommer les paramètres d’une fonction.

def ma_fonction(a, b, c):print(a, b, c)

ma_fonction(c="a", a="b", b="c")

Résultat:

b c a

Cela permet également de changer l’ordre des arguments de la fonction.

Valeurs par défaut

Il est possible de donner une valeur par défaut aux paramètres des fonctions.

def ma_fonction(a, b=5, c=6):print(a, b, c)

ma_fonction(1)ma_fonction(1, 2)ma_fonction(1, 2, 3)

Résultat:

1 5 61 2 61 2 3

1.2.6 Récursivité

Une fonction peut s’appeler elle-même, directement ou indirectement.

def fact(n):if n <= 1:

return 1else:

return n*fact(n-1)

fact(5)

Résultat:

120

Pensez à une condition d’arrêt. Attention aux boucles sans fin !

def inf(n):return inf(n + 1)

try:inf(0)

except RuntimeError as e:print("Erreur: \"{0}\"".format(e))

1.2. Les fonctions 27

Page 32: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Erreur: "maximum recursion depth exceeded"

1.2.7 Visibilité des variables

• Chaque fonction crée sa propre pile

• Une fonction a accès à ses variables locales et aux variables globales

• Si une variable locale a le même nom qu’une variable globale, c’est la variable locale qui sera accessible

• Pour changer la valeur d’une variable globale dans une fonction, il faut utiliser le mot clef global

"""Une fonction voit l'espace mémoire "global",mais ne le modifie pas."""a = 5b = 6c = 7def ma_fonction(c):

b = 7print("a={0}, b={1}, c={2}".format(a, b, c))

ma_fonction("$")print("a={0}, b={1}, c={2}".format(a, b, c))

Résultat:

a=5, b=7, c=$a=5, b=6, c=7

"""Partage de l'espace mémoire "global""""a = 5b = 6c = 7def ma_fonction(c):

global ba = 8b = 7print("a={0}, b={1}, c={2}".format(a, b, c))

ma_fonction("$")print("a={0}, b={1}, c={2}".format(a, b, c))

Résultat:

a=8, b=7, c=$a=5, b=7, c=7

"""Imbrication des espaces mémoires."""a = 5b = 6c = 7

def ma_fonction(c):global ba = 8

28 Chapter 1. Sommaire

Page 33: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

b = 7print("* a={0}, b={1}, c={2}".format(a, b, c))

def ma_sous_fonction():global ab = 32a = 0print("** a={0}, b={1}, c={2}".format(a, b, c))

ma_sous_fonction()

ma_fonction("$")print("a={0}, b={1}, c={2}".format(a, b, c))

Résultat:

* a=8, b=7, c=$

** a=0, b=32, c=$a=0, b=7, c=7

1.2.8 Paramètres définis à la volée

Il est possible pour une fonction d’accepter n’importe quel argument (déconseillé).

Nombre variable d’arguments

def une_nouvelle_fonction(*arguments):for arg in arguments:

print(arg, )print()

une_nouvelle_fonction("abcd", 0, 2, [1, 2, 3, 4], {"a": 5, "b": 6})

Résultat

abcd 0 2 [1, 2, 3, 4] {'a': 5, 'b': 6}

Il est possible de passer une collection.

une_nouvelle_fonction(*"abcd")une_nouvelle_fonction(*[1, 2, 3, 4])une_nouvelle_fonction(*{"a": 5, "b": 6})

Résultat:

a b c d1 2 3 4a b

Avec des paramètres nommés:

def une_nouvelle_fonction(**arguments):for clef in arguments:

print("{0}:{1}".format(clef, arguments[clef]), )print()

une_nouvelle_fonction(a=5, b="6")

1.2. Les fonctions 29

Page 34: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Résultat

a:5 b:6

Il est également possible de passer une collection.

une_nouvelle_fonction(**{"a": 9, "b": 16})

Résultat:

a:9 b:16

1.2.9 Pour aller plus loin

Une fonction est une valeur comme une autre

def fa(a):return a ** 2

ma_var = faprint(ma_var(5))

Résultat:

25

def accepte_une_fonction(f, v):return int(f(v))

print(accepte_une_fonction(ma_var, 6.48074069841))print(accepte_une_fonction(fa, 6.48074069841))

Résultat:

4242

Une fonction peut créer une autre fonction

Cette fonction “capture” les variables.

def f0(a):def f0_0():

return a*2return f0_0

ma_var2 = f0(21)ma_var3 = f0(42)print(ma_var2())print(ma_var3())

Résultat:

4284

30 Chapter 1. Sommaire

Page 35: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Syntaxe courte: les lambdas

ma_var4 = lambda a : a * 2print(ma_var4(21))

Résultat:

42

Les first-class functions

En informatique, un langage de programmation possède des first-class functions s’il traite une fonctioncomme tous ses autres types.

Les prédicats

Un prédicat est une fonction qui retourne “Vrai” ou “Faux” en fonction de critères qui lui sont propres. Idéalement, lavaleur “Vrai” ou “Faux” du prédicat ne doit dépendre que des arguments de celui-ci.

"""Prédicat qui nous dit si la valeur de l'entier a est plus grande que 10"""def au_dessus_de_10(a):

return a >= 10

print(au_dessus_de_10(5), au_dessus_de_10(11))

Résultat:

False True

Utilisation

mon_tableau = [1764, 49, 25, 9, 0, -16, 25, -9, 4, 64]print(list(filter(au_dessus_de_10, mon_tableau)))

[1764, 49, 25, 25, 64]

1.2.10 Prédicats anonymes: les lambdas

mon_tableau = [1764, 49, 25, 9, 0, -16, 25, -9, 4, 64]resultat = filter(lambda a: a<0, mon_tableau)print(list(resultat))# exemple d'utilisation:for i in resultat:

print(i)# ou encore:[i for i in resultat]

Résultat du print:

[-16, -9]

1.2. Les fonctions 31

Page 36: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Syntaxe: lambda arg0 [, arg1, [arg2, ...]] : code

La dernière expression de la section code de lambda correspond à la valeur retournée.

lambda a: a<0print(list(filter(lambda a: a<0, mon_tableau)))

Résultat:

[-16, -9]

# est équivalent àdef inf_a_0(a):

return a<0print(list(filter(inf_a_0, mon_tableau)))

Résultat:

[-16, -9]

1.2.11 Traitement de données par fonctions

Il existe plusieurs traitements standards sur les données de type sequences en python:

• filter(): qui, comme nous l’avons vu, permet de filtrer nos données selon un critère exprimé par un prédicat

• map(): qui applique un traitement à chaque élément

map

def un_exemple(a):if a > 0:

return a+42else:

return a-100

mon_tableau = [1764, 49, 25, 9, 0, -16, 25, -9, 4, 64]data = map(un_exemple, mon_tableau)print(list(data))

Résultat:

[1806, 91, 67, 51, -100, -116, 67, -109, 46, 106]

1.2.12 Exercices

Bonjour

Écrire une fonction affiche_bonjour qui affiche “Bonjour”.

Modifier cette fonction pour qu’elle prenne en paramètre nom et prenom pour afficher:

Bonjour UnNom UnPrénom

32 Chapter 1. Sommaire

Page 37: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Opérations

Écrire les 4 fonctions suivantes qui permettent respectivement de multiplier, diviser, additionner et soustraire de nom-bre a et b:

• mul(a, b)

• div(a, b)

• add(a, b)

• sub(a, b)

Modifier la fonction dvi() afin de gérer l’erreur ZeroDivisionError et d’afficher dans ce cas soit -inf (-float(“inf”)),soit +inf (float(“inf”)).

Vous pourrez tester le bon fonctionnement de votre code avec les appels suivants:

mul(21, 2)div(84, 2)div(4, 0)div(-3, 0)add(40, 2)sub(60, 18)

Correction

def div(a, b):"""Division de a par b.

:param a: un entier:param b: un entier:return: un float, a / b"""try:

r = a / bexcept ZeroDivisionError:

if a < 0:r = -float("inf")

else:r = float("inf")

return r

Listes

Les données suivantes seront utilisées pour l’exercice:

import randomLIST_DATA = [4.1, 9, 0, "coucou", -1000, 1000, [ 0, 1], "42",

-float("inf"), 18, -49, -4999.0, -455, float("inf"), -541, 9999.9,float("nan")]

LIST_DATA.extend(4.2 * random.randint(-1000, 1000) for r in range(20))CHAINE = "abcd0ef9ghij8klmA5BCD7EFG6HIJK4LMNO3PQR2STU1VWXYZnopqrstuvwxyz"

Écrire un filtre à l’aide d’une fonction lambda qui va sélectionner seulement les données de type entières et flottantesdans LIST_DATA.

1.2. Les fonctions 33

Page 38: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Écrire un filtre à l’aide d’une fonction lambda qui va sélectionner seulement les données comprise entre [-1000 et1000[ dans LIST_DATA.

Utiliser map() sur le résultat précédent afin d’obtenir une liste de valeurs absolues.

Écrire un filtre à l’aide d’une fonction lambda qui va sélectionner seulement les caractères entre ‘e’ et ‘n’ et entre ‘E’et ‘N’ dans CHAINE.

1.3 Les modules

• Un module est un bloc de code réutilisable en python. Ce bloc de code peut-être importé par un autre bloc decode. Il existe plusieurs types de module : les modules Python, les modules d’extension et les packages.

• Les modules Python sont comme leur nom l’indique écrit en python dans un fichier ayant comme extension.py (.pyc et/ou .pyo). Ils sont parfois appelés «pure module». Le nom du module est le nom du fichier (sansl’extension) accessible via la variable globale ‘‘__name__‘‘.

• Les modules d’extension sont des modules écrits en langage bas-niveau utilisable par Python : C/C++ pourPython ou Java pour Jython. Ces modules sont généralement contenus dans un seul fichier pré-compilé etchargeable dynamiquement comme par exemple un objet partagé (fichier .so) sous unix, une DLL sous windowsou une classe java. On parle également de modules «built-in», lorsqu’il s’agit de modules de la bibliothèquestandard (les bibliothèques logicielles de base du langage distribuées avec l’interpréteur Python) écrit en C.

• Un package est un module qui contient d’autres modules. Un package est généralement un répertoire contenantun fichier ‘‘__init__.py‘‘.

• Il existe un package particulier qui est le «root package». C’est la racine dans la hiérarchie des paquets. lagrande majorité de la bibliothèque standard est dans le «root package».

1.3.1 Présentation

Lancer votre éditeur de texte pour créer un fichier python appelé fibo.py dans le répertoire courant et contenant cebout de code :

%%file fibo.py#! /usr/bin/env python3# -*- coding: utf-8 -*-"""Module nombres de Fibonacci"""

# Fibonacci numbers module

def fib(n): # write Fibonacci series up to na, b = 0, 1while b < n:

print(b),a, b = b, a + b

def fib2(n): # returns Fibonacci series up to nresult = []a, b = 0, 1while b < n:

result.append(b)a, b = b, a + b

return result

34 Chapter 1. Sommaire

Page 39: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Une fois ce fichier créé, lancer l’interpréteur via la commande python et importer le module créé :

>>> import fibo

Une fois le module importé, vous pouvez accéder aux méthodes et variables via son nom.

>>> fibo.fib(1000)1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987>>> fibo.fib2(100)[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89]>>> fibo.__name__'fibo'

• Un module peut contenir aussi bien des déclarations (statements) que des définitions de fonctions.

• Les déclarations sont destinées à initialiser le module.

• Elles sont exécutées seulement lors du premier import du module (pour forcer le rechargement, il faut utiliserreload())

• Chaque module possède son propre espace de nommage (ou table de nommage) «privé» qui est globalpour toutes les fonctions de ce même module. Les variables sont accessibles via la notation «nommod-ule.nomvariable» (comme pour une fonction)

• Un module peut importer d’autres modules. Par convention, on place tous les imports au début du module.

• L’instruction «import» crée un objet de type module contenant toutes les données et fonctions du module, etajoute une variable désignant ce module au sein de l’espace de nommage du programme/module/interpéteurqui fait l’import. Il existe une variante qui permet d’importer directement dans la table de nommage un ou deséléments particuliers du module : from module import nom

• Par exemple :

>>> from fibo import fib, fib2>>> fib(500)1 1 2 3 5 8 13 21 34 55 89 144 233 377

Dans cet exemple, fib et fib2 sont ajoutés dans la table de nommage locale. Fibo n’est pas défini. On peutaussi utiliser le symbole * qui va importer toute la table de nommage sauf ceux qui contiennent un tiret-bas(underscore : _ )

1.3.2 Exécution d’un module

Pour exécuter un module Python, on utilise cette commande :

$> python fibo.py <arguments\>

Le code va être exécuté comme lors d’un import mais la valeur de la variable name est alors égale à main. En ajoutantce bout de code à la fin de votre module :

if __name__ == "__main__":import sysfib(int(sys.argv[1]))

vous rendrez ce fichier utilisable comme un script ou comme un module.

$ python fibo.py 501 1 2 3 5 8 13 21 34

Pour rappel, si le module est importé, le code du main ne sera pas exécuté :

1.3. Les modules 35

Page 40: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

>>> import fibo>>>

Enfin, il est possible d’exécuter un module python comme un script Unix en ajoutant :

#! /usr/bin/env python3

en début de fichier. Le module sera alors exécutable (à condition que les droits sur le fichier le permette après unchmod u+x ./fibo.py par exemple) via la commande

$> ./fibo.py <arguments>

1.3.3 Le «path»

Quand un module nommé spam est importé, l’interpreteur cherche en premier ce nom dans les modules intégrés. S’ilne le trouve pas, il va ensuite chercher un fichier nommé spam.py d’une liste de répertoires donnée par la variablesys.path.

>>> import sys>>> sys.path['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/pymodules/python2.7']

sys.path contient le répertoire courant, le PYTHONPATH et les dépendances par défaut de l’installation python.

1.3.4 Les modules Compilés

• Pour accélerer le chargement des modules, une version compilée (ou pré-compilée) du module est présentedans le même répertoire. La compilation est faite automatiquement par Python si le module est plus récent quel’éventuelle compilation disponible. Cette dernière possède l’extension .pyc.

• la compilation n’augmente pas la vitesse d’exécution mais la vitesse de chargement du module.

• Il ne s’agit que d’une version convertie en «byte code» du module qui est donc indépendante de la plateformed’exécution. Les modules .pyc peuvent donc être partagés (on parle de portabilité).

1.3.5 Les modules standards

• Python fournit toute une bibliothèque de modules standards décrite dans un document séparé : la Python LibraryReference.

• Certains modules sont intégrés à l’interpréteur (selon par exemple le système d’exploitation : winreg est fourniuniquement sur les systèmes Windows) et permettent un accès aux opérations qui ne font pas partie du noyaude la langue (dir ou help que nous allons voir après par exemple) pour améliorer l’efficacité ou un accès à desprimitives du système d’exploitation (sys qui est fourni dans chaque interpréteur Python).

>>> import sys>>> sys.ps1'>>> '>>> sys.path['', '/usr/lib/python2.7', '/usr/lib/python2.7/plat-linux2', '/usr/lib/python2.7/lib-tk', '/usr/lib/python2.7/lib-old', '/usr/lib/python2.7/lib-dynload', '/usr/local/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages', '/usr/lib/python2.7/dist-packages/PIL', '/usr/lib/pymodules/python2.7']

Vous pouvez faire un *sys.path.append* pour ajouter un répertoire de développement utilisable par différents mod-ules.

36 Chapter 1. Sommaire

Page 41: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

1.3.6 La fonction dir()

La fonction intégrée dir() renvoie la liste des noms définis par un module.

>>> import fibo>>> dir(fibo)['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'fib', 'fib2']

Sans argument, la fonction dir() liste les noms que l’on a actuellement définis :

>>> import fibo>>> dir(fibo)['__builtins__', '__doc__', '__file__', '__name__', '__package__', 'fib', 'fib2']>>> a = [1, 2, 3, 4, 5]>>> import sys>>> dir()['__builtins__', '__doc__', '__name__', '__package__', 'a', 'fibo', 'sys']

• ‘‘__builtins__‘‘ est l’espace de noms contenant toutes les fonctions et variables intégrées

• ‘‘__doc__‘‘ contient l’aide du module

• ‘‘__file__‘‘ contient le nom du fichier Python contenant le module

• ‘‘__name__‘‘ contient le nom du module

• ‘‘__package__‘‘ contient le nom du package contenant le module

>>> fibo.__doc__'\nModule nombres de Fibonacci\n'>>> print fibo<module 'fibo' from 'fibo.py'>>>> fibo.__file__'fibo.py'>>> fibo.__name__'fibo'>>> fibo.__package__>>>

1.3.7 La fonction help()

• Aide en ligne Python.

• la commande help() place l’interpréteur en mode d’aide

>>> help()

Welcome to Python 2.7! This is the online help utility.

If this is your first time using Python, you should definitely check outthe tutorial on the Internet at http://docs.python.org/2.7/tutorial/.

Enter the name of any module, keyword, or topic to get help on writingPython programs and using Python modules. To quit this help utility andreturn to the interpreter, just type "quit".

To get a list of available modules, keywords, or topics, type "modules","keywords", or "topics". Each module also comes with a one-line summaryof what it does; to list the modules whose summaries contain a given wordsuch as "spam", type "modules spam".

1.3. Les modules 37

Page 42: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

help> figono Python documentation found for 'figo'

• help(module) renvoie l’aide du module

>>> import fibo>>> help(fibo)Help on module fibo:

NAMEfibo - # Fibonacci numbers module

FILE/root/fibo.py

FUNCTIONSfib(n)

fib2(n)

• help(module.methode) renvoie l’aide de la méthode

** Ajoutons de l’aide à notre module fibo : **

%%file fibo_help.py#! /usr/bin/env python3# -*- coding: utf-8 -*-

"""Fibonacci numbers module"""

def fib(n): # write Fibonacci series up to n"""do : write Fibonacci series up to nparameters : n as numberreturn : void"""a, b = 0, 1while b < n:

print b,a, b = b, a + b

def fib2(n): # returns Fibonacci series up to nresult = []a, b = 0, 1while b < n:

result.append(b)a, b = b, a + b

return result

** Voici le résultat :**

>>> reload(fibo)<module 'fibo' from 'fibo.py'>>>> help(fibo)Help on module fibo:

38 Chapter 1. Sommaire

Page 43: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

NAMEfibo - Fibonacci numbers module

FILE/root/fibo.py

FUNCTIONSfib(n)

do : writes Fibonacci series up to nparameters : n as numberreturn : void

fib2(n)

1.3.8 Les packages

• Les packages sont une façon de structurer l’espace de noms des modules Python en utilisant le «dotted modulenames» (nom de module avec des points). Par exemple, le module nommé A.B désigne un module nommé Bdans le package nommé A.

• Si on prend l’exemple d’un projet de traitement de fichier texte, il existe un grand nombre de formats (.txt,.xml, .csv, .json, etc) et vous pouvez avoir un grand nombre d’opération de traitement à effectuer (compression,exportation, etc)

• Voici un exemple de structure possible pour ce projet :

traitement/ Racine du package__init__.py Initialise le package traitementformats/ Subpackage pour les formats de fichiers

__init__.pycsv.pyjson.pytxt.pyxml.py...

compression/ Subpackage pour la compression__init__.pyzip.pytar.py...

exportation/ Subpackage pour l’exportation__init__.pypdf.pyhtml.py...

• Lors de l’importation d’un package, Python cherche dans les répertoires du sys.path à la recherche du sous-répertoire du paquet.

• Dans l’exemple ci-après, lors de l’instruction import calculatrice, Python trouve le sous-répertoirecalculatrice dans le répertoire /Library/Python/2.7/site-packages contenu dans le sys.path

>>> import sys>>> sys.path['', ..., '/Library/Python/2.7/site-packages']>>> import calculatrice

1.3. Les modules 39

Page 44: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

>>> calculatrice.__file__'/Library/Python/2.7/site-packages/calculatrice/__init__.pyc'

• Les fichiers ‘‘__init__.py‘‘ permettent d’indiquer que le répertoire est un package. Ils permettent d’exécuter ducode lors de l’initialisation (instancier la variable ‘‘__all__‘‘ par exemple).

• On peut importer un module du package ci-dessus avec cette commande :

import traitement.formats.csv

• Cette commande charge le module traitement.formats.csv. Pour l’utiliser, il devra être référencé par son nomcomplet tel qu’importé :

>>> traitement.formats.csv.read('file1.csv')

• Une autre façon d’importer un «sous-module» est :

from traitement.formats import csv

• Cette commande charge le module csv et le rend disponible sans le préfixe du package. De cette manière, lafonction read est utilisable de cette manière :

>>> csv.read('file1.csv')

• Enfin, si on a besoin seulement de la fonction read, on peut la charger directement :

from traitement.formats.csv import read

• Cette dernière fonction charge quand même le module csv mais rend la fonction read directement disponible :

>>> read('file1.csv')

• Attention : quand vous utilisez la commande from package import item, l’item peut être un module(ou un sous-package) du package mais également un autre nom défini dans un module comme une variable, unefonction ou une classe.

• L’instruction import teste en premier si l’élément est défini dans le paquet sinon il suppose que c’est unmodule et tente de le charger. Si le module n’est pas trouvé, l’exception ImportError est levée.

• Si vous utilisez par contre la syntaxe import item.subitem.subsubitem, chaque item excepté ledernier doit être un package. Le dernier peut être un module ou un package mais ne peut être une variable,une fonction ou une classe.

• Lorsque l’on importe paquet.module pour la première fois, cela crée l’objet paquet correspondant (et son espacede noms) et exécute le fichier __init__.py correspondant. Ce dernier est exécuté seulement la premièrefois. Le fichier __init__.py peut créer des données et des fonctions au sein de l’objet correspondant aupackage, c’est pourquoi lors de l’exécution de l’instruction import paquet.nom, Python cherche d’abordune variable ou fonction dans l’objet correspondant au paquet, avant de chercher un module ou un paquet dansle répertoire du paquet.

1.3.9 Complément d’information

• L’instruction from package import \* est déconseillée. Cette instruction va lancer le parcours des mod-ules du package et faire toutes les importations. Cela peut prendre donc un certain temps et l’importation desmodules peut générer des conflits dans la table de nommage. L’auteur du package peut fournir une liste explicitedes modules à importer grâce à la variable __all__ dans le fichier __init__.py du package.

40 Chapter 1. Sommaire

Page 45: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

__all__ = ["csv", "json", "txt", "xml"]

• Enfin, pour les import «intra-package», on peut utiliser les références relatives.

• Par exemple, depuis le module zip, on peut utiliser ces commandes :

from . import tarfrom .. import formatsfrom ..exportation import pdf

1.3.10 Distribuez votre projet : le packaging

• Une distribution est une collection de modules Python distribués ensembles comme une ressource téléchargeableet destinée à être installée. Il existe énormément de distributions de modules comme PIL (the Python ImagingLibrary), PyXML, etc.

• Pour faire le lien entre la distribution et la plateforme de destination, on utilise des classes intermédiaires ap-pelées packagers. Les packagers vont prendre les sources et les compiler pour effectuer une «release». Ainsiles utilisateurs finaux vont pouvoir installer les modules sans difficultés. Distutils est un packagers qui va vouspermettre facilement de distribuer votre code.

• La librairie Distutils regroupe l’ensemble des utilitaires python pour la distribution de modules. Pour distribuervotre code, il faudra écrire un script d’installation (nommé setup.py par convention) et éventuellement écrire unfichier de configuration d’installation.

• Ensuite, il vous faudra créer une ressource distribuable (souvent une archive) et optionnellement créer une ouplusieurs distributions compilées.

• Le script setup est généralement assez simple. Voici un premier exemple :

from distutils.core import setupsetup(name='foo',

version='1.0',py_modules=['foo'],)

• La plupart des informations sont fournies comme argument à la fonction setup.

• Ces arguments peuvent être regroupés en deux catégories : les metadata du package (nom, version) et lesinformations sur ce qu’est, ce que fait le package.

• Les modules sont spécifiés par leur nom d’objet et non leur nom de fichier. Il est recommandé de fournir desmetadata supplémentaire comme son nom, son adresse mail et une url de projet :

– Vous pouvez lister des modules individuellement : py_modules = [’mod1’, ‘pkg.mod2’]

– ou lister des packages entier : packages=[’distutils’, ‘distutils.command’] Ici on spécifie des modules purpython par package plutôt que de lister tous les modules de ce paquet.

– par exemple ce package :

setup.pysrc/

mypkg/__init__.pymodule.pydata/

tables.datspoons.datforks.dat

1.3. Les modules 41

Page 46: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

– pourrait avoir un setup comme cela :

setup(...,packages=['mypkg'],package_dir={'mypkg': 'src/mypkg'},package_data={'mypkg': ['data/*.dat']},)

• Voici une liste non exhaustive d’argument de la fonction setup

– le nom du projet : nom=”sample”

– la version : version=”1.2.0” (voir PEP440)

– les packages à inclure dans le projet. On peut les lister ou utiliser find_packages pour automatiser cettetache (exclude pour pour exlure ceux qui ne doivent pas etre installé) : py_modules=[’foo’],

– Metadonnées: Il est important d’inclure des métadonnées à propose de votre projet.

# A description of your projectdescription='A sample Python project',long_description=long_description,

# The project's main homepageurl='https://github.com/pypa/sampleproject',

# Author detailsauthor='The Python Packaging Authority',author_email='[email protected]',

# Choose your licenselicense='MIT',

# See https://pypi.python.org/pypi?%3Aaction=list_classifiersclassifiers=[

# How mature is this project? Common values are# 3 - Alpha# 4 - Beta# 5 - Production/Stable'Development Status :: 3 - Alpha',

# Indicate who your project is intended for'Intended Audience :: Developers','Topic :: Software Development :: Build Tools',

# Pick your license as you wish (should match "license" above)'License :: OSI Approved :: MIT License',

# Specify the Python versions you support here. In particular, ensure# that you indicate whether you support Python 2, Python 3 or both.'Programming Language :: Python :: 2','Programming Language :: Python :: 2.6','Programming Language :: Python :: 2.7','Programming Language :: Python :: 3','Programming Language :: Python :: 3.2','Programming Language :: Python :: 3.3','Programming Language :: Python :: 3.4',

],

# What does your project relate to?keywords='sample setuptools development',

42 Chapter 1. Sommaire

Page 47: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

• Enfin, il est possible d’ajouter :

– Les dépendances : install_requires = [’peppercorn’] “install_requires” est utilisé pour spécifier quellesdépendances sont nécessaire au projet pour fonctionner. Ces dépendances seront installés par Pip lors del’installation de votre projet.

– Fichiers additionnels : package_data = { ‘sample’: [’package_data.dat’]}

• Voici un exemple plus complet :

#!/usr/bin/env python

from distutils.core import setup

setup(name='Distutils',version='1.0',description='Python Distribution Utilities',author='Greg Ward',author_email='[email protected]',url='https://www.python.org/sigs/distutils-sig/',packages=['distutils', 'distutils.command'],

)

• Vous pouvez également inclure d’autre fichier au package comme un *README* pour expliquer le projet etun *MANIFEST* pour définir des fichiers supplémentaire à inclure dans la distribution du projet packaté.

• Pour créer une distribution des fichiers sources du module, il faut donc créer un script d’installation (setup.py)contenant le code ci-dessus et d’executer la commande

$>python setup.py sdist [$>sdist setup.py sous windows]

• sdist va créer une archive (tarball sous unix et zip sous windows) contenant le script setup.py et le module. Lefichier d’archive sera nommé foo-1.0.tar.gz (ou .zip) et sera décompressé dans un répertoire foo-1.0.

• Pour installer le module, après avoir télécharger et décompresser l’archive, il faut se déplacer dans le répertoirecréer par la décompression de l’archive et taper la commande suivante :

$>python setup.py install

• Cette commande va copier les fichiers dans le répertoire réservé aux modules tiers de l’installation Python.

• Remarque : On note donc que c’est le même script qui sert pour la distribution et l’installation.

• On peut faciliter encore plus l’installation des modules distribués. Par exemple, sous windows, on peut créer uninstallateur executable avec cette commande :

$>python setup.py bdist_wininst

• Cette commande var créer un exe nommé foo-1.0.win32.exe dans le répertoire courant.

• Il existe également d’autre format de distribution : le rpm avec bdist_rpm, le pkgtool (bdist_pkgtool) et le hp_uxswinstall (bdist_sdux)

• Vous pouvez lister les formats de distribution disponibles avec cette commande :

$>python setup.py bdist -help-formats

Pour installer des packages, on vous conseille d’utiliser Pip (Python installing package). Cet outil cherche les packagessur le Python Package Index (PyPi). Les packages python peuvent être compacté dans des archives tarball ou zip.Python utilise des formats de distribution. Actuellement, Python utilise egg mais ce format va etre peu à peu remplacé

1.3. Les modules 43

Page 48: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

par wheel. Pour construire votre package, vous pouvez donc utiliser wheel et pour envoyer votre package sur Pypi, ilfaut utiliser l’outil twine

1.4 Programmation objet

1.4.1 La définition de classes

Généralités

La création d’une nouvelle classe peut être considérée comme la création d’un nouveau type de données, défini parle développeur. Par convention, les noms de classe sont généralement typographié en “CamelCase”. Dans l’exempleci-dessous, l’exécution de l’instruction class provoque la création d’un objet de type class, et lui assigne commenom Vecteur. Comme n’importe quelle entité de Python, la classe créée est placée dans un module (ici __main__puisque l’instruction class est soumise directement à l’interpréteur).

class Vecteur(object):pass

print Vecteur

<class '__main__.Vecteur'>

De même qu’un type prédéfini de Python (par exemple float ou list) possède de multiples valeurs (par exemple3.14 ou []), une classe peut donner naissance à de multiples objets. On dit de chacun de ces objets qu’il est une“instance” de la classe. Pour créer une telle instance, on utilise le nom de la classe comme si c’était un nom defonction (utilisation de parenthèses). Dans l’exemple ci-dessous, l’instruction provoque la création d’une instance detype Vecteur, et lui assigne comme nom v.

v = Vecteur()

print v

<__main__.Vecteur object at 0x00000000042B80F0>

Données membres

Tout comme un nombre flottant est composé de sous-parties (mantisse, exposant, signe...), une instance est appelée àcontenir des données nommées, accessibles indivuellement par l’opérateur .. Les données membres peuvent être lues,créées et modifiées à tout moment et par n’importe qui.

v.x = 1v.y = 2print v.x

1

print v.y

2

del v.yprint v.y

44 Chapter 1. Sommaire

Page 49: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

---------------------------------------------------------------------------AttributeError Traceback (most recent call last)

<ipython-input-5-3a2cca00cd27> in <module>()1 del v.y

----> 2 print v.y

AttributeError: 'Vecteur' object has no attribute 'y'

Méthodes

Imaginons ci-dessous que l’on souhaite doter nos nouveaux vecteurs d’un calcul de norme et d’une transformation detype homothétie. Pour uniformiser, on définit également une fonction pour initialiser les attributs d’une instance, etune fonction d’affichage :

class Vecteur(object):pass

def init(v,x=0,y=0):v.x = xv.y = y

def norme(v):x2 = v.x**2y2 = v.y**2return (x2+y2)**(1./2.)

def homothetie(v,n):v.x = v.x * nv.y = v.y * n

def affiche(v):print v.x, v.y

v = Vecteur()init(v,3,-4)print norme(v)

5.0

homothetie(v,3)affiche(v)

9 -12

On peut être rapidement confronté à des conflits de noms avec d’autres fonctions similaires pour d’autres classes, eton aimerait que nos nouvelles fonctions ne soient utilisées qu’avec notre nouvelle classe Vector. Pour ce faire, nousallons en faire des méthodes en les insérant dans la classe.

Une méthode est une fonction “attachée” à une classe particulière. La définition des méthodes est faite à l’intérieur dela définition de la classe.

Dans la définition d’une méthode, le premier paramètre désigne l’instance courante sur laquelle on veut appliquer laméthode. Pour exécuter une méthode sur une instance particuliere, on utilise l’opérateur ”.”, comme pour les donnéesmembres, puis des parenthèses pour signifier qu’il s’agit d’une fonction. L’instance à gauche du ”.” est alors passée àla méthode en tant que premier paramètre.

1.4. Programmation objet 45

Page 50: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

class Vecteur(object):def init(self,x=0,y=0):

self.x = xself.y = y

def norme(self):x2 = self.x**2y2 = self.y**2return (x2+y2)**(1./2.)

def homothetie(self,n):self.x = self.x * nself.y = self.y * n

def affiche(self):print self.x, self.y

v = Vecteur()v.init(3,-4)print v.norme()

5.0

v.homothetie(3)v.affiche()

9 -12

Encapsulation

Données membres et méthodes sont collectivement appelés “attributs”. On place généralement les données dans lesinstances (et elles varient d’une instance à l’autre), par contreet les méthodes sont placées dans la classe.

En programmation orientée objet orthodoxe, il est préconisé d’interdire un accès direct aux données par les codesclients extérieurs, et de forcer ces clients à passer par l’intermédiaire de méthodes de lecture (qu’on appelle “getters”)et de méthodes de modification (qu’on appelle “setters”).

Python ne permet pas vraiment d’interdire l’accès aux données, mais seulement de les masquer. Pour ce faire, donnezleur un nom qui commence par “__”. les données sont alors dites “pseudo-privées”.

Dans l’exemple ci-dessous, les attributs x et y de Vector ont été rendus pseudo-privés, la méthode init() faitoffice de “setter” global (méthode pour changer les valeurs de x et y), et les méthodes getx() et gety() font officede “getters”.

class Vecteur(object):

def init(self,u=0,v=0):self.__x = uself.__y = v

def getx(self):return self.__x

def gety(self):return self.__y

v = Vecteur()v.init(3, -4)print v.getx(), v.gety()

46 Chapter 1. Sommaire

Page 51: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

3 -4

print v.x, v.y

---------------------------------------------------------------------------AttributeError Traceback (most recent call last)

<ipython-input-17-9166e99d7851> in <module>()----> 1 print v.x, v.y

AttributeError: 'Vecteur' object has no attribute 'x'

print v.__x, v.__y

---------------------------------------------------------------------------AttributeError Traceback (most recent call last)

<ipython-input-16-e70456a59924> in <module>()----> 1 print v.__x, v.__y

AttributeError: 'Vecteur' object has no attribute '__x'

Documentation

Les “docstrings” habituelles fonctionnent avec les classes.

class MaClasse(object):"Documentation de MaClasse"__data = []def ma_methode():

"documentation de ma_methode()"pass

print MaClasse.__doc__

Documentation de MaClasse

print MaClasse.ma_methode.__doc__

documentation de ma_methode()

help(MaClasse)

Help on class MaClasse in module __main__:

class MaClasse(__builtin__.object)| Documentation de MaClasse|| Methods defined here:|| ma_methode()| documentation de ma_methode()|| ----------------------------------------------------------------------| Data descriptors defined here:

1.4. Programmation objet 47

Page 52: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

|| __dict__| dictionary for instance variables (if defined)|| __weakref__| list of weak references to the object (if defined)

1.4.2 Les méthodes spéciales

Constructeur et destructeur

Le constructeur est une méthode spéciale, appelée __init__(), qui est appelée lors de la création d’une instancede classe.

Le destructeur est une méthode spéciale, appelée __del__(), qui est appelée lors de la destruction d’une instance.ATTENTION : on ne contrôle pas vraiment le moment ou le destructeur est appelé. De ce fait, il est rarement utilisé.

class Vector(object):def __init__(self,u=0,v=0):self.__x = uself.__y = v

def getx(self):return self.__x

def gety(self):return self.__y

def norm(self):x2 = self.__x**2y2 = self.__y**2return (x2+ y2)**(1/2)

v1 = Vector(3, 4)print v1.getx(), v1.gety()

3 4

v2 = Vector(-2, 7)print v2.getx(), v2.gety()

-2 7

Affichage

Par défaut, l’affichage d’une instance renvoie son nom de classe et son adresse en mémoire :

class Vector(object):def __init__(self,u=0,v=0):self.__x = uself.__y = v

v = Vector(3,4)

print v

<__main__.Vector instance at 0x00000000054CC2C8>

48 Chapter 1. Sommaire

Page 53: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

v

<__main__.Vector instance at 0x00000000054CC2C8>

On peut personnaliser cet affichage en s’appuyant sur les méthodes spéciales __str()__ et __repr()__.

class Vector(object):def __init__(self,u=0,v=0):self.__x = uself.__y = v

def __str__(self):return "(%.0f,%.0f)" % (self.__x,self.__y)

def __repr__(self):return "Vector(%.0f,%.0f)" % (self.__x,self.__y)

v = Vector(3,4)

print v

(3,4)

v

Vector(3,4)

En cas d’affichage destiné à l’utilisateur, tel qu’un appel à print, c’est la méthode __str__ qui est recherchée enpriorité, et seulement en dernier recours la méthode __repr__. En principe, cette dernière est supposé retourner untexte qui, si il était exécuté, recréerait l’objet original.

Objets-fonctions

En dotant une classe de la méthode __call__, les instances de cette classe peuvent être utilisés comme des fonc-tions. On parle d’objets-fonctions. Cela peut-être utile lorsqu’on veut utiliser un programme générique qui attend unefonction en paramètre, et que l’on veut lui donner à la place des objets qui savent se comporter en fonction, tout enayant des paramètres internes.

class Multiplier(object):def __init__(self,constant):

self.constant = constantdef __call__(self,other):

return self.constant*other

m2 = Multiplier(2)print m2(6)print map(m2,[1,2,3,4,5])

12[2, 4, 6, 8, 10]

Ce mécanisme est souvent le plus sain pour associer des données persistantes à une fonction, plutôt que l’utilisationde variables globales, de fonctions imbriquées, ou de valeurs par défaut modifiables.

Opérateurs mathématiques

Il est possible de permettre l’utilisation des opérateurs habituels avec vos nouvelles classes, en redéfinissant des méth-odes spéciales au nom imposé :

1.4. Programmation objet 49

Page 54: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

• + : __add__(self,other)

• - : __sub__(self,other)

• * : __mul__(self,other)

• / : __truediv__(self,other)

• // : __floordiv__(self,other)

• % : __mod__(self,other)

• ** : __pow__(self,other)

class Vector(object):def __init__(self,u=0,v=0):self.__x = uself.__y = v

def __add__(self, other):if isinstance(other, Vector):

newx = self.__x + other.__xnewy = self.__y + other.__yreturn Vector(newx, newy)

def __str__(self):return "(%.0f,%.0f)" % (self.__x,self.__y)

v1 = Vector(2, 3)v2 = Vector(-4, 7)v3 = v1 + v2

print v3

(-2,10)

Index de séquence

A l’aide de la méthode __getitem__(), on peut implémenter l’opérateur [] sous toutes ses formes :

class MonTexte(object):def __init__(self,value):

self.data = valuedef __getitem__(self,index):

return self.data[index]

txt = MonTexte("Bonjour")print txt[2]

n

print txt[-1::-1]

ruojnoB

En bonus, la présence de __getitem__ permet d’utiliser un objet au sein d’une boucle for. L’interpréteur va invo-quer cette méthode avec des valeurs entières croissantes, en commencant par 0, et jsuqu’à l’émission d’une exceptionIndexError.

for c in txt: print c

50 Chapter 1. Sommaire

Page 55: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

En réalité, la présence de __getitem__ permet d’utiliser un objet dans de multiples autres “contextes d’itération”,tels que qu’un test d’appartenance in, une “compréhension de liste”, la fonction prédéfinie map, l’assignation deséquences, ...

'i' in txt

False

[c for c in txt]

['B', 'o', 'n', 'j', 'o', 'u', 'r']

map(ord,txt)

[66, 111, 110, 106, 111, 117, 114]

(c1, c2, c3, c4, c5, c6, c7) = txtc3, c2, c1

('n', 'o', 'B')

list(txt), tuple(txt), '-'.join(txt)

(['B', 'o', 'n', 'j', 'o', 'u', 'r'],('B', 'o', 'n', 'j', 'o', 'u', 'r'),'B-o-n-j-o-u-r')

1.4.3 Les objets composés

Généralités

Un objet peut contenir des objets, qui peuvent contenir des objets, qui. . . On peut descendre dans les niveaux successifsen enchainant les ”.” .

class Vecteur(object): passclass Impulsion(object) : pass

imp = Impulsion()imp.vitesse = Vecteur()imp.vitesse.x = 1.imp.vitesse.y = 0.imp.vitesse.z = 0.imp.masse = 10.

print ( imp.vitesse.x, imp.vitesse.y, imp.vitesse.z, imp.masse )

(1.0, 0.0, 0.0, 10.0)

(Non)Chainage des constructeurs

Dans un constructeur, il n’y a pas d’appel automatique aux constructeurs des sous-parties de l’objet courant, commecela existe dans d’autres langages. Un objet n’a pas d’obligation de contenir des données, et donc tout ce qui est ajoutédoit l’être explicitement, y compris dans les constructeurs.

1.4. Programmation objet 51

Page 56: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

class Vecteur(object):def __init__(self):

self.x = 0self.y = 0self.z = 0

def __str__(self):return "%d|%d|%d" % ( self.x, self.y, self.z )

class Impulsion(object):def __init__(self):

self.vitesse = Vecteur()self.masse = 0

def __str__(self):return "%s|%d" % ( self.vitesse.__str__(), self.masse )

i1 = Impulsion()print "(%s)" % i1

(0|0|0|0)

Du point de vue de l’affectation, de la copie, de la comparaison, et de beaucoup d’autres opérations, un objet secomporte essentiellement comme un dictionnaire contenant des attributs.

Affectation et copie

Lorsqu’on affecte un objet à une variable, il n’y a pas de copie. Comme d’habitude, cela génère une nouvelle variablequi référence le même objet original. Dans l’exemple ci-dessous, on voit que si je modifie un attribut de i2, i1 estégalement modifié.

i2 = i1i2.masse = 1print "(%s), (%s)" % ( i2, i1 )

(0|0|0|1), (0|0|0|1)

Pour dupliquer un objet, on peut avoir recours au module copy, et à sa fonction copy. Ainsi, si je modifie maintenantun attribut de i2, l’attribut correspondant de i1 est inchangé.

import copyi2 = copy.copy(i1)i2.masse = 2print "(%s), (%s)" % ( i2, i1 )

(0|0|2|2), (0|0|2|1)

Mais il s’agit d’une copie de surface. L’équivalent d’une affectation des attributs un à un :

i2 = Impulsion()i2.vitesse = i1.vitesse # i2 = copy.copy(i1)i2.masse = i1.masse # i2 = copy.copy(i1)i2.masse = 2print "(%s), (%s)" % ( i2, i1 )

(0|0|0|2), (0|0|0|1)

Comme au début, pour i2 = i1, l’instruction i2.vitesse = i1.vitesse ne duplique pas l’instance deVecteur, mais fait en sorte que i2.vitesse et i1.vitesse désigne la même instance. Ainsi, si on change

52 Chapter 1. Sommaire

Page 57: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

un attribut de i2.vitesse, on agit également sur i1.vitesse :

i2.vitesse.z = 2print "(%s), (%s)" % ( i2, i1 )

(0|0|2|2), (0|0|2|1)

Si on souhaite dupliquer intégralement un objet et tous ses attributs à tous les niveaux, on préfèrera la fonctiondeepcopy. Dans l’exemple suivant, on modifie un sous-sous-attribut de i2, sans affecter i1.

i2 = copy.deepcopy(i1)i2.vitesse.y = 3print "(%s), (%s)" % ( i2, i1 )

(0|3|2|1), (0|0|2|1)

Egalité et identité

Malheureusement, à la différence d’un dictionnaire, l’opérateur de comparaison == n’est pas capable de vérifier récur-sivement l’égalité de tous les données membres de l’objet. A la place, il se contente de vérifier que les deux variablesdésignent le même objet, à la façon d’un is. Pour obtenir le comportement “logique”, il faut par exemple redéfinir lesopérateurs __eq__et __ne__ à tous les niveaux :

class Vecteur(object):def __init__(self,x=0,y=0,z=0):

self.__x = xself.__y = yself.__z = z

def __str__(self):return "%d|%d|%d" % ( self.__x, self.__y, self.__z )

class Impulsion(object):def __init__(self,x=0,y=0,z=0,m=0):

self.__vitesse = Vecteur(x,y,z)self.__masse = m

def __str__(self):return "%s|%d" % ( self.__vitesse.__str__(), self.__masse )

i1 = Impulsion(1,2,3,4)

import copyi2 = copy.deepcopy(i1)

(i1 is i2, i1==i2, i1!=i2)

(False, False, True)

class Vecteur(object):def __init__(self,x=0,y=0,z=0):

self.__x = xself.__y = yself.__z = z

def __str__(self):return "%d|%d|%d" % ( self.__x, self.__y, self.__z )

def __eq__(self,other):return ( self.__x==other.__x ) and ( self.__y==other.__y ) and ( self.__z==other.__z )

1.4. Programmation objet 53

Page 58: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

class Impulsion(object):def __init__(self,x=0,y=0,z=0,m=0):

self.__vitesse = Vecteur(x,y,z)self.__masse = m

def __str__(self):return "%s|%d" % ( self.__vitesse.__str__(), self.__masse )

def __eq__(self,other):return ( self.__vitesse==other.__vitesse ) and ( self.__masse==other.__masse )

i1 = Impulsion(1,2,3,4)

import copyi2 = copy.deepcopy(i1)

(i1 is i2, i1==i2, i1!=i2)

(False, True, True)

class Vecteur:def __init__(self,x=0,y=0,z=0):

self.__x = xself.__y = yself.__z = z

def __str__(self):return "%d|%d|%d" % ( self.__x, self.__y, self.__z )

def __eq__(self,other):return ( self.__x==other.__x ) and ( self.__y==other.__y ) and ( self.__z==other.__z )

def __ne__(self,other): return not(self==other)

class Impulsion:def __init__(self,x=0,y=0,z=0,m=0):

self.__vitesse = Vecteur(x,y,z)self.__masse = m

def __str__(self):return "%s|%d" % ( self.__vitesse.__str__(), self.__masse )

def __eq__(self,other):return ( self.__vitesse==other.__vitesse ) and ( self.__masse==other.__masse )

def __ne__(self,other): return not(self==other)

i1 = Impulsion(1,2,3,4)

import copyi2 = copy.deepcopy(i1)

(i1 is i2, i1==i2, i1!=i2)

(False, True, False)

1.4.4 L’héritage entre classes

Généralités

Python permet d’exprimer une relation “est une sorte de” entre deux classes. Si B est une sorte de A, on s’attend à ceque les instances de B possède les attributs (données et méthodes) de cette classe, mais aussi tous ceux de A, puisqueces objets sont aussi une sorte de A. On dit que B hérite de A, ou dérive de A. On peut aussi qualifier A de “classemère”, de “classe de base”, de “super-classe”, et B de “classe dérivée”, de “classe fille”, de “sous-classe” de A.

54 Chapter 1. Sommaire

Page 59: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Pour hériter d’une classe mère, il suffit d’indiquer son nom entre parenthèses après le nom de la classe fille. La classefille a accès à tous les attributs de la classe mère. En d’autres termes, quand on écrit obj.x, l’interpréteur cherche xdans l’instance, puis dans sa classe, puis dans la classe mère de cette classe, etc.

La classe prédéfinie object sert de classe de base commune à toutes les classes “nouveau style” de Python. Assurez-vous toujours que vos classes héritent d’object, directement ou indirectement, sans quoi vous perdrez un grandnombre de fonctionnalités du Python moderne.

class A(object):def x(self): return "A"def y(self): return "A"

class B(A):def z(self): return "B"

b = B()

print b.x(), b.y(), b.z()

A A B

Surcharge

Une classe dérivée peut ajouter de nouveaux attributs, qu’il s’agisse de données ou de méthodes. Elle peut aussiredéfinir un des attributs de la classe de base, auquel cas, pour les instances de la classe dérivée, c’est la nouvelledéfinition qui sera trouvée la première, et utilisée. On parle de “surcharge”.

class A(object):def x(self): return "A"def y(self): return "A"def z(self): return "A"

class B(A):def x(self): return "B"def t(self): return "B"

b = B()

print b.x(), b.y(), b.z(), b.t()

B A A B

Héritage multiple

Une classe peut hériter de plusieurs autres en même temps (on donne alors une liste de noms séparés par des virgules).L’ordre de gauche à droite des classes parentes est respecté lorsque l’interpréteur Python recherche un nom (donnéeou méthode).

class A1(object):def x(self): print "A1"

class A2(object):def x(self): print "A2"

class B(A1,A2):pass

1.4. Programmation objet 55

Page 60: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

b = B()b.x()

A1

Arborescence d’héritage

En plus de l’héritage multiple, chaque classe de base peut à son tour hériter d’une autre classe, etc. L’ensemble desclasses dont hérite une instance forme ainsi une arborescence parfois complexe. Dans cette arborescence, la recherched’un attribut se fait de bas en haut et de gauche à droite, en profondeur d’abord, mais en faisant en sorte qu’uneclasse de base ne soit jamais explorée avant que toutes ses dérivées le soient. Ainsi, dans l’exemple ci-dessous, A estprioritaire sur C, mais pas sur B2 :

class A(object):def x(self): return "A"def y(self): return "A"def z(self): return "A"

class B1(A):pass

class B2(A):def x(self): return "B2"

class C(object):def y(self): return "C"def z(self): return "C"

class D(B1,B2,C):z = C.z

d = D()print d.x(), d.y(), d.z()

B2 A C

L’ordre de parcours des classes est appelé le MRO (Method Resolution Order).

On voit aussi, dans l’exemple ci-dessus, que l’on peut explicitement copier la méthode z de C dans D. Ainsi, tout appelà la méthode z pour une instance de D se trouve redirigé vers la méthode de C (au lieu de A).

Chaque recherche d’attribut est indépendante et repart de self

Lorsque j’appelle une méthode m1 de l’objet obj, cette méthode est recherchée dans l’arborescence de classes de obj.Si, à son tour, m1 appelle une autre méthode m2, la recherche de m2 repart de obj (et pas de la classe de m1). En C++,on dirait que toutes les méthodes sont virtuelles et toutes les variables polymorphiques.

class A(object):def x(self): return "A"def y(self): return "A"def affichex(self): print self.x()

class B1(A):pass

class B2(A):

56 Chapter 1. Sommaire

Page 61: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

def x(self): return "B2"

class C(object):def x(self): return "C"def affichey(self): print self.y()

class D(B1,B2,C):pass

d = D()d.affichex()d.affichey()

B2A

Reutiliser explicitement une méthode de base

Lorsqu’une méthode est redéfinie dans une classe dérivée, on dit qu’elle est surchargée. Plutôt que de réécrire toutesles instructions, il peut être utile de commencer par éxécuter le code de la méthode de la classe de base. C’estparticulièrement vrai pour les méthodes spéciales, telles que les constructeurs.

class Fruit(object):def __init__(self, couleur, variete=''):

self.__couleur= couleurself.__variete= variete

def __str__(self):if (self.__variete!=''):

return "%s %s" % (self.__variete,self.__couleur)else:

return "fruit %s" % self.__couleur

class Pomme(Fruit):def __init__(self, couleur, variete='golden'):

Fruit.__init__(self,couleur,variete)def __str__(self):

return ("pomme " + Fruit.__str__(self))

p = Pomme('rouge')

print p

pomme golden rouge

On peut remplacer l’appel explicite à la classe de base par un appel à la fonction prédéfinie super(), en lui passantle nom de la classe courante et l’instance courante. Dans le cas d’un héritage simple, cela permet ensuite de revoir lesclasse de base sans avoir à corriger tous les appels directs aux méthodes de la classe de base.

class Pomme(Fruit):def __init__(self, couleur, variete='golden'):

super(Pomme,self).__init__(couleur,variete)def __str__(self):

return ("pomme " + Fruit.__str__(self))

p = Pomme('rouge')

print p

1.4. Programmation objet 57

Page 62: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

pomme golden rouge

Cependant, le nom super() est un faux ami, car en cas d’héritage multiple, il y a plusieurs super-classes. En réalitéce que renvoie la fonction super(), c’est un objet intermédiaire, qui va rechercher l’attribut demandé en suivant lechemin habituellement parcouru en cas d’héritage (MRO).

class A(object):def x(self): return "A"

class B1(A):pass

class B2(A):def x(self): return "B2"

class C(B1,B2):def x(self):

return super(C,self).x()

c = C()print c.x()

B2

PYTHON 3 SEULEMENT : on peut appeler super() sans arguments, ce qui permet notamment de renommer une classesans avoir à corriger tous les appels à super().

1.4.5 Sauvegarde et reconstruction d’objets

Généralités

• Les objets sont dit “persistants” lorsqu’ils ne disparaissent pas à la fin du programme Python en cours. Celaconsiste en général à les “sérialiser”, c’est à dire en produire une représentation binaire compacte, et à stockercette représentation dans un fichier.

• En Python, la persistance repose sur des modules de la libraire standard, tels que pickle et shelve.

Pickle / cPickle

• Ce module est capable de transformer en flot d’octets n’importe quel objet en mémoire. Ces octets peuvent êtreécrits dans un fichier, envoyés par réseau, etc.

• A l’inverse, le module peut lire et recrée en mémoire les objets d’un fichier, l’un après l’autre.

• Quand c’est disponible, préférez cPickle, écrit en C et plus rapide.

• ATTENTION : pas de garantie de portabilité de vos données entre des plateformes différentes.

class Vecteur:def __init__(self,u=0,v=0):

self.x = uself.y = v

def __str__(self):return "(%.0f,%.0f)" % (self.x,self.y)

v1 = Vecteur(1,2)v2 = Vecteur(3,4)

58 Chapter 1. Sommaire

Page 63: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

import pickle

fw = open('vecteurs.pkl','w')pickle.dump(v1,fw)pickle.dump(v2,fw)fw.close()

fr = open('vecteurs.pkl','r')print pickle.load(fr)print pickle.load(fr)fr.close()

(1,2)(3,4)

• documentation python 2

• documentation python 3

Shelve

• Ce module permet de ranger des objets dans un fichier, non pas séquentiellement, mais en les associant à desnoms.

• Le fichier est manipulé comme si il s’agissait d’un dictionnaire.

class Vecteur:def __init__(self,u=0,v=0):

self.x = uself.y = v

def __str__(self):return "(%.0f,%.0f)" % (self.x,self.y)

import shelve

s = shelve.open('vecteurs.db')s['v1'] = Vecteur(1,2)s['v2'] = Vecteur(3,4)s.close()

#...

s = shelve.open('vecteurs.db')print s.keys()print s['v1']print s['v2']s.close()

• documentation python 2

• documentation python 3

1.4. Programmation objet 59

Page 64: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

1.4.6 Compléments

Attributs cachés

Dans un objet, les attributs ordinaires sont stockés dans un attribut spécial nommé __dict__. Chaque instancepossède également un attribut nommé __class__ qui pointe vers sa classe.

Dans une classe, on trouve également des attributs spéciaux : * __doc__: documentation de la classe, * __dict__: attributs de la classe, * __name__ : nom de la classe, * __bases__ : tuple contenant les classes de bases de laclasse courante. * __mro__ : ordre de parcours des ancêtres de la classe. * __module__ : nom du module où laclasse est définie (__main__ en mode interactif).

class A1 : passclass A2 : pass

class B(A1,A2):def __init__(self,value): self.data = valuedef display(self) : print "data:", self.data

b = B("abc")

print b.__dict__

print b.__dict__['data']

abc

print ( b.__class__, )

(<class __main__.B at 0x0000000004206588>,)

print b.__class__.__name__

B

print b.__class__.__bases__

(<class __main__.A1 at 0x0000000004180EE8>, <class __main__.A2 at 0x00000000042065E8>)

print b.__class__.__dict__

{'__module__': '__main__', 'display': <function display at 0x000000000422A588>, '__init__': <function __init__ at 0x000000000422A5F8>, '__doc__': None}

Attributs pseudo-privés

Au sein d’une instruction composée class, tous les noms qui sont préfixés par un double souligné __ (et non à lafin), sont “magiquement” manipulés par l’interpréteur Python qui insère devant le nom un simple souligné _ et le nomde la classe courante. Ainsi, les attributs recoivent un nom qui devient spécifique à la classe, et qui ne risque plusd’être redéfini par erreur dans les classes dérivées. On parle d’attributs “pseudo-privés”, non pas parce que l’accès àces attributs est véritablement interdit, mais parce que l’altération automatique de leurs noms complique leur accès del’extérieur.

class Demo:public_data = "public data"__private_data = "private data"def public_method(self): print "public method()"

60 Chapter 1. Sommaire

Page 65: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

def __private_method(self): print "private method()"

dir(Demo)

['_Demo__private_data','_Demo__private_method','__doc__','__module__','public_data','public_method']

print Demo.public_data

public data

print Demo.__private_data

---------------------------------------------------------------------------AttributeError Traceback (most recent call last)

<ipython-input-9-5a651a2f66b8> in <module>()----> 1 print Demo.__private_data

AttributeError: class Demo has no attribute '__private_data'

print Demo._Demo__private_data

private data

d = Demo()d.public_method()

public method()

d.__private_method()

---------------------------------------------------------------------------AttributeError Traceback (most recent call last)

<ipython-input-24-f98a2e3c7104> in <module>()----> 1 d.__private_method()

AttributeError: Demo instance has no attribute '__private_method'

d._Demo__private_method()

private method()

A la différence d’autres langages, toutes les données d’un objet réside dans l’objet lui-même, quelle que soit la classeet la méthode à l’origine de ces données. Cela peut générer des interactions involontaires, en particulier dans le casd’un héritage multiple venant de classes issues de développeurs indépendants. Les attributs pseudo-privés évitent cesinteractions non voulues.

class C1(object):def set1(self): self.__X = 1def get1(self): return self.__X

1.4. Programmation objet 61

Page 66: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

class C2(object):def set2(self): self.__X = 2def get2(self): return self.__X

class C3(C1,C2): pass

obj = C3()obj.set1()obj.set2()print obj.get1(), obj.get2()

1 2

Propriétés

On peut définir dans une classe des attributs particuliers de type “propriété” (property). Ces propriétés ressemblentà des variables membres, et s’utilisent comme des variables membres, mais en réalité le fait de lire une propriétédéclenche l’utilisation du “getter” qui lui est attaché, et le fait d’affecter une nouvelle valeur à cette propriété déclenchel’utilisation du “setter” attaché (si et seulement si il est défini). Typiquement, “getter” et “setter” manipulent unevariable interne pseudo-privée.

Ci-dessous, nous définissons pour la classe Vector des propriétés x et y, dont la lecture déclenche un appel àgetx() ou gety(), qui renvoient les valeurs des variables pseudo-privées __x ou __y des instances de Vector.Seule la propriété x a été associée à un “setter”. y, en l’absence de “setter”, est en lecture seule : on ne peut pas luiaffecter de valeur (par contre on peut le faire sur __y via init()).

class Vector(object):def init(self,u=0,v=0):self.__x = uself.__y = v

def getx(self):return self.__x

def setx(self,u):self.__x = u

x = property(getx,setx)def gety(self):return self.__y

y = property(gety)

v = Vector()v.init(3, -4)print v.x, v.yv.x = 2print v.x

3 -42

v.y = 5

---------------------------------------------------------------------------AttributeError Traceback (most recent call last)

<ipython-input-29-916c9ff1d97a> in <module>()----> 1 v.y = 5

62 Chapter 1. Sommaire

Page 67: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

AttributeError: can't set attribute

Ce qui est remarquable ici, c’est que Python ne force pas une encapsulation précoce et inutile. On peut très biendévelopper une première version de classe avec des attributs publics, avoir des clients, puis décider ultérieurementd’en faire des propriétés, si le besoin s’en fait sentir.

On a vu aussi, dans notre exemple, qu’il est facile de faire des propriétés “read-only” en ne déclarant que les “getters”.Il est cependant plus classique de fournir à la fois la méthode de lecture et d’écriture, notamment pour controler qu’onn’enregistre que des valeurs valides dans une propriété. Par exemple, si nos vecteurs ne peuvent contenir que desvaleurs entre -1 et 1 :

class Vector(object):def init(self,u=0,v=0):self.x = uself.y = v

def getx(self):return self.__x

def setx(self,x):if (x<-1): self.__x = -1elif (x>1): self.__x = 1else: self.__x = x

x = property(getx,setx)def gety(self):return self.__y

def sety(self,y):if (y<-1): self.__y = -1elif (y>1): self.__y = 1else: self.__y = y

y = property(gety,sety)

v = Vector()v.init(3, -4)print v.x, v.y

1 -1

Variables de classe

On peut ajouter des données à une classe (et pas seulement des méthodes), auquel cas elles sont en quelque sortepartagées et visibles pour toutes les instances de la classe.

En effet, quand vous demandez à lire la donnée nommée x de l’instance obj, ce qui se note obj.x, l’interpréteurPython cherche d’abord le nom dans l’instance elle-même, puis à défaut dans la classe, puis dans ses ancêtres, commepour n’importe quel attribut.

Dans l’exemple ci-dessous, on dote la classe Vecteur de variable x et y qui contiennent des valeirs par défaut pourles instances. On peut créer ces variables directement lors de la création de classe, comme nous le faisons pour x, oul’ajouter ultérieurement, comme nous le faisons pour y.

class Vecteur(object) :x = 0

Vecteur.y = 0

v = Vecteur()

1.4. Programmation objet 63

Page 68: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

print Vecteur.x, Vecteur.yprint v.x, v.y

0 00 0

Par contre, si vous affectez une nouvelle valeur à obj.x, et que ce nom n’existe pas encore dans l’instance, un nouvelattribut est créé à cette occasion, dans l’instance. Formulons le à nouveau : en cas de lecture, l’interpréteur cherchel’attribut dans l’instance concernée, puis dans sa classe et ses ancêtres, mais en cas d’affectation d’une nouvelle valeur,l’attribut est ajouté à l’instance si il n’existe pas déjà.

v.x, v.y = 10, 20

print Vecteur.x, Vecteur.yprint v.x, v.y

0 010 20

Un langage très dynamique

Les instructions class et les instructions def, sont traitées à l’exécution comme n’importe quelles instructions. Ellesretournent des objets, certes un peu spéciaux, et leur assigne un nom dans l’espace de nom courant. Avec ces objets,on peut réaliser des manipulations impossibles dans d’autres langages, comme par exemple créer une méthode d’aborden tant que fonction, à l’extérieur de la classe, puis la rattacher à posteriori.

class A(object):def __init__(self,value): self.data = valuedef display(self) : print "data:", self.data

a = A('bonjour')

def my_display_upper(self):print "data:", self.data.upper()

A.display_upper = my_display_upper

a.display_upper()

data: BONJOUR

Une méthode peut s’invoquer à travers le nom de classe, mais dans ce cas il ne faut pas oublier de redonner le nom del’objet à traiter comme premier argument (self) :

A.display_upper(a)

data: BONJOUR

Je peux toujours aussi appeler directement la fonction à travers son nom original (my_display_upper) :

my_display_upper(a)

data: BONJOUR

On peut même s’amuser, comme ci-dessous, à décrocher la fonction de la classe (en effacant le nom), et à l’accrocherdirectement à l’instance. Mais dans ce cas, la définition automatique de self n’est pas réalisée (ce mécanisme n’estactif que pour les fonctions attachées dans des classes). On doit alors redonner a comme argument à l’appel defonction.

64 Chapter 1. Sommaire

Page 69: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

del A.display_upper

a.display_upper = my_display_upper

a.display_upper(a)

data: BONJOUR

Les encoches

La définition dans une classe d’un attribut spécial nommé __slots__ permet de limiter la liste des attributs autorisés(sans pour autant les créer). Cela permet d’éviter des erreurs de frappe involontaire, de faire certaines optimisations,mais en contre-partie cela peut affecter l’existence de l’attribut spécial __dict__, et perturber le fonctionnementd’outils génériques qui s’appuient sur ce dictionnaire interne.

class DemoSlots(object):__slots__ = ['att1','att2']

ds = DemoSlots()print ds.att1

---------------------------------------------------------------------------AttributeError Traceback (most recent call last)

<ipython-input-26-c8617deaf333> in <module>()34 ds = DemoSlots()

----> 5 print ds.att1

AttributeError: att1

ds.att1 = "this is att1"print ds.att1

this is att1

ds.att3 = "this is att3"

---------------------------------------------------------------------------AttributeError Traceback (most recent call last)

<ipython-input-40-3f4ad9ce7b2c> in <module>()----> 1 ds.att3 = "this is att3"

AttributeError: 'DemoSlots' object has no attribute 'att3'

class DerivedSlots(DemoSlots): passds = DerivedSlots()ds.att3 = "this is att3"

Méthodes statiques et méthodes de classe

Imaginons que l’on veuille compter le nombre d’instances créées par une classe. Pour récupérer le nombre courantd’instances, on peut écrire une méthode qui ne se sert que de l’attribut de classe, et cette méthode devrait pouvoir être

1.4. Programmation objet 65

Page 70: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

appelée via le nom de classe, sans passer par une instance, mais cela ne fonctionne pas à l’aide d’une implémentation“naive” telle que celle-ci :

class DemoComptage(object):__nb_objets = 0def __init__(self):

DemoComptage.__nb_objets = DemoComptage.__nb_objets+1def nb_objets():

return __nb_objets

a = DemoComptage()b = DemoComptage()c = DemoComptage()

print DemoComptage.nb_objets()

---------------------------------------------------------------------------TypeError Traceback (most recent call last)

<ipython-input-1-225b71655857> in <module>()10 c = DemoComptage()11

---> 12 print DemoComptage.nb_objets()

TypeError: unbound method nb_objets() must be called with DemoComptage instance as first argument (got nothing instead)

En effet, même si self n’est pas utilisé dans le corps d’une méthode, l’interpréteur Python exige qu’une méthodesoit invoquée à travers une instance. L’attribut nb_objets de la classe est évidemment accessible à tous, donc ilpeut êtr lu directement par les clients, mais si on tient à préserver l’encapsulation, une simple fonction extérieure peutfaire l’affaire :

class DemoComptage(object):nb_objets = 0def __init__(self):

DemoComptage.nb_objets = DemoComptage.nb_objets+1

def nb_objets():return DemoComptage.nb_objets

a = DemoComptage()b = DemoComptage()c = DemoComptage()

print nb_objets()

3

Cependant, pour satisfaire les programmeurs qui tiennent à localiser la fonction au sein de la classe, depuis Python2.2, on peut définir des méthodes dites “statiques”, qui peuvent s’invoquer sans passer par une instance :

class DemoComptage(object):_nb_objets = 0def __init__(self):

DemoComptage._nb_objets = DemoComptage._nb_objets+1def nb_objets():

return DemoComptage._nb_objetsnb_objets = staticmethod(nb_objets)

66 Chapter 1. Sommaire

Page 71: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

a = DemoComptage()b = DemoComptage()c = DemoComptage()

print DemoComptage.nb_objets()

3

Il existe également des méthodes dites “de classe”, qui recoivent en premier argument non pas l’instance courante,mais la classe courante.

class DemoClassMethod(object):def m(cls,data):

print cls, datam = classmethod(m)

DemoClassMethod.m("bonjour")

<class '__main__.DemoClassMethod'> bonjour

Décorateurs de fonctions

Les méthodes statiques et les méthodes de classes sont des cas particuliers de “décorateurs” de fonction.

Un décorateur est une fonction qui manipule une fonction. Il peut effectuer une action une fois pour toute, et renvoyerla fonction originale, ou bien renvoyer une nouvelle fonction qui effectuera des manipulations à chaque appel, avantde le répercuter à la fonction originale qui aura été mémorisée en interne.

Par exemple, lors de l’instruction nb_objets = staticmethod(nb_objets), on appelle le décorateurstaticmethod, qui substitue à la fonction nb_objets originale une autre fonction, dont le rôle sera, à chaqueappel, de mettre de côté le premier argument (self) et de transmettre les autres à la fonction nb_objets originale.

On peut maintenant définir plus facilement une décoration, à l’aide du caractère @ :

class DemoDeco(object):_nb_objets = 0def __init__(self):

DemoDeco._nb_objets += 1@staticmethoddef nb_objets():

return DemoDeco._nb_objets@classmethoddef m(cls,data):

print cls, data

a = DemoDeco()b = DemoDeco()c = DemoDeco()

print DemoDeco.nb_objets()

3

DemoDeco.m("bonjour")

<class '__main__.DemoDeco'> bonjour

On peut empiler autant de décorateurs que souhaités. Le code ci-dessous :

1.4. Programmation objet 67

Page 72: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

@A @B @Cdef f():

...

est l’équivalent de :

def f():...

f = A(B(C(f)))

On peut bien sur écrire ses propres décorateurs. On les implémente en général à l’aide d’une classe qui stocke lafonction décorée, et définit l’opérateur d’appel __call__. Par exemple, ci-dessous, une classe qui compte les appelsà la fonction décorée :

class compteur(object):def __init__(self,func):

self.func = funcself.count = 0

def __call__(self,*args):self.count += 1print 'call %s to %s' % (self.count,self.func.__name__)self.func(*args)

@compteurdef bidon(texte):

print texte

bidon("bonjour")

call 1 to bidonbonjour

bidon("bonsoir")

call 2 to bidonbonsoir

Enfin, notons qu’il existe des décorateurs permettant de simplifier la définition des propriétés d’une classe (attributsdont l’accès en lecture et/ou en écriture est confié à des méthodes). L’exemple de vecteur précédemment vu peut-êtreréécrit ainsi :

class Vector(object):def init(self,u=0,v=0):self.x = uself.y = v

@propertydef x(self):return self.__x

@x.setterdef x(self,u):if (u<-1): self.__x = -1elif (u>1): self.__x = 1else: self.__x = u

@propertydef y(self):return self.__y

@y.setterdef y(self,v):if (v<-1): self.__y = -1

68 Chapter 1. Sommaire

Page 73: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

elif (v>1): self.__y = 1else: self.__y = v

v = Vector()v.init(3, -4)print v.x, v.y

1 -1

Hériter d’un type prédéfini

On peut hériter des types prédéfinis, comme de n’importe quelle autre classe. ATTENTION, dans l’exemple ci-dessous, comme on hérite d’une classe “non-modifiable” (“immutable”), on ne peut pas redéfinir ‘‘__init__‘‘, quiintervient après a création de l’instance ; on est obligé de passer par une redéfinition de ‘‘__new__‘‘.

class FloatWithUnit(float):def __new__(cls,value,unit):

instance = float.__new__(cls,value)instance.unit = unitreturn instance

def __str__(self):return float.__str__(self)+" "+self.unit

def __mul__(self,other):return FloatWithUnit(float.__mul__(self,other),self.unit+"*"+other.unit)

largeur = FloatWithUnit(2,"cm")longueur = FloatWithUnit(5,"cm")print largeur*longueur

10.0 cm*cm

Les classes de style ancien

Toutes les explications de cette formation concerne les classes de nouveau style, apparue avec 2.2, et qu’il faut utiliserà chaque fois que c’est possible. Comment savoir si une classe est d’ancien ou nouveau style ? * avant 2.2 : toutes lesclasses sont de stype ancien * de 2.2 à 2.x : les classes qui ont la classe object parmi leurs ancêtres sont de nouveaustyle. * à partir de 3 : toutes les classes sont de nouveau style

Un grand nombre de fonctionnalités avancées ne sont disponibles que pour les classes de nouveau style : super(),propriétés, encoches, méthodes statiques, décorateurs, héritage d’un type prédéfini...

Par ailleurs, en cas d’héritage en losange, les comportements son subtilement différents. Pour les classes de nouveaustyle, la recherche d’attribut se fait en profondeur d’abord, puis de gauche à droite, à une exception près : les classesdérivées sont toujours explorées avant leurs classes de base. Cette exception n’avait pas cours pour les classes de styleancien :

class A: x = "A"class B1(A): passclass B2(A): x = "B2"class C(B1,B2): pass

print C.x

A

En cas de nouveau style :

1.4. Programmation objet 69

Page 74: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

class A(object): x = "A"class B1(A): passclass B2(A): x = "B2"class C(B1,B2): pass

print C.x

B2

Pour éviter toute ambiguité, quel que soit le style de classe, on peut dire explicitement quelle est la méthode à utiliser :

class A: x = "A"class B1(A): passclass B2(A): x = "B2"class C(B1,B2): x = B2.x

print C.x

B2

Itérateurs

Aujourd’hui, avant de rechercher une méthode __getitem__, l’interpréteur Python cherche d’abord une méthode__iter__, qui peut implémenter des schémas d’itération plus complexes. La méthode __iter__ est supposéeretourné un objet “itérateur”, sur lequel on va ensuite appeler la méthode next (en python 3 : __next__), quirenvoit un nouvel élément à chaque appel, et lève une exception StopIteration lorsqu’il n’y a plus d’éléments.

class ReverseIterator(object):def __init__(self, seq):

self.seq = seqself.index = len(seq.data)

def next(self):if self.index == 0:

raise StopIterationself.index = self.index - 1return self.seq.data[self.index]

class Reverse(object):def __init__(self, data):

self.data = datadef __iter__(self):

return ReverseIterator(self)

for char in Reverse('123'):print(char)

321

Notre classe peut servir elle aussi dans tous les contextes d’itération.

inverse = Reverse('123')[c for c in inverse]

['3', '2', '1']

70 Chapter 1. Sommaire

Page 75: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

[c for c in inverse]

['3', '2', '1']

[c+d for c in inverse for d in inverse]

['33', '32', '31', '23', '22', '21', '13', '12', '11']

Pour éviter d’avoir à écrire deux classes, on peut être tenté de dire qu’objet est son propre itérateur, et de placer laméthode next() dans la classe d’origine (exemple ci-dessous). Dans la pratique, c’est peu utile, car l’objet ne peutêtre itéré qu’une seule fois. On peut alors être tenté d’ajouter une méthode raz() qui remettrait l’index à 0, maisavec encore une limite : impossible de lancer deux itérations simultanées. Ne rusez pas : faites deux classes.

class Reverse(object):def __init__(self, data):

self.__data = dataself.__index = len(data)

def __iter__(self):return self

def next(self):if self.__index == 0:

raise StopIterationself.__index = self.__index - 1return self.__data[self.__index]

inverse = Reverse('123')print [c for c in inverse]print [c for c in inverse]

['3', '2', '1'][]

class Reverse(object):def __init__(self, data):

self.__data = dataself.__index = len(data)

def __iter__(self):return self

def next(self):if self.__index == 0:

raise StopIterationself.__index = self.__index - 1return self.__data[self.__index]

def raz(self):self.__index = len(self.__data)

inverse = Reverse('123')print [c for c in inverse]inverse.raz()print [c for c in inverse]inverse.raz()print [c+d for c in inverse for d in inverse]

['3', '2', '1']['3', '2', '1']['32', '31']

1.4. Programmation objet 71

Page 76: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

1.5 Les tests

1.5.1 Pourquoi écrire des tests ?

Lorsque l’on écrit un programme, il est généralement constitué de plusieurs fonctions que l’on assemble afin dedécrire notre algorithme permettant de nous donner la réponse à notre problème. Un programme n’est pas forcémentun développement sur un temps court.

On voit beaucoup de bibliothèques scientifiques qui ont plus de dix ans. Les fonctions peuvent donc être écrites àdifférents moments avec des échelles de temps bien différentes. On peut par exemple ajouter une fonctionnalité à unbout de code plusieurs années après en avoir écrit le coeur.

Si il est primordial d’écrire de la documentation pour comprendre ce qui est fait, il est également judicieux d’écriredes tests pour s’assurer du bon fonctionnement de notre programme.

Il faut noter que certains types de développement logiciel s’appuient sur les tests (Test Driven Development).

1.5.2 Les types de tests

On peut citer trois types de tests primordiaux permettant de s’assurer au mieux de l’absence de bugs dans notreprogramme. Un programme n’est jamais à 100% sûr.

• les tests unitaires,

• les tests d’intégration,

• les tests du système complet.

Tests unitaires: niveau 0

Le but est de tester chaque petit bout de code: fonctions, méthodes, ...

Ils permettent d’être sûr que chaque brique de votre programme fonctionne correctement indépendamment des autres.

Néanmoins, ils ne permettent pas d’assurer le bon fonctionnement du programme dans sa globalité.

Tests d’intégration: niveau 1

Le but est de commencer à tester de petites interactions entre les différentes unités du programme.

Ces tests peuvent être réalisés avec les mêmes outils que ceux utilisés dans les tests unitaires.

Mais il y a une différence importante: on suppose que les unités prises une à une sont valides.

Tests du système complet: niveau 2

Le but est de tester le programme dans sa globalité.

On assemble à présent toutes les briques pour un problème concret.

Là encore, si les 2 premiers niveaux sont négligés les tests du système complet ne servent à rien.

Les tests sont donc écrits à des stades différents du développement mais ont chacun leur importance. Un seul de cestrois types de tests ne suffit pas pour tester l’intégrité du programme.

Les tests unitaires et les tests d’intégration sont généralement testés avec les mêmes outils.

72 Chapter 1. Sommaire

Page 77: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Pour le dernier type de tests, on prendra des exemples concrets d’exécution et on testera la sortie avec une solutioncertifiée.

1.5.3 Notre cas d’étude

Nous allons calculer les coefficients de la suite de Fibonacci en utilisant les coefficients binomiaux. Les coefficientsbinomiaux se calculent à partir de la formule suivante(

nk

)= Ck

n =n!

k!(n− k)!pour k = 0, · · · , n.

On en déduit alors le calcul des coefficients de la suite de Fibonacci par la formule suivante

n∑k=0

(n− kk

)= F (n + 1).

Voici un exemple de code Python implantant cette formule (fibonacci.py)

1 #!/usr/bin/env python2

3

4 def factorielle(n):5 """Calcul de n!6

7 >>> factorielle(0)8 19 >>> factorielle(5)

10 12011

12 """13 if n == 1 or n == 0:14 return 115 else:16 return n * factorielle(n - 1)17

18

19 def somme(deb, fin, f, fargs=()):20 """Calcul de21

22 $$23 \sum_{k=deb}^fin f(k, *fargs)24 $$25

26 test d'une suite arithmetique27 >>> somme(0, 10, lambda k:k)28 55.029

30 test d'une suite geometrique31 >>> somme(1, 8, lambda k: 2**k)32 510.033

34 """35 som = 0.36 for k in range(deb, fin + 1):37 som += f(k, *fargs)38 return som39

1.5. Les tests 73

Page 78: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

40

41 def coef_binomial(n, k):42 """Calcul de $C_n^k$43

44 :param n: un entier45 :param k: un entier46 :return: float47

48 >>> coef_binomial(4, 2)49 650

51 """52 if k > n or k < 0:53 return 0.54 return factorielle(n) / (factorielle(k) * factorielle(n - k))55

56

57 def fibonacci(n):58 """Renvoie la liste des n premiers termes de la suite de Fibonacci59

60 >>> fibonacci(10)61 [1, 1, 2, 3, 5, 8, 13, 21, 34, 55]62

63 """64 def g(k, n):65 return coef_binomial(n - k, k)66

67 fibo = []68 for i in range(n):69 fibo.append(int(somme(0, i, g, fargs=(i,))))70

71 return fibo72

73

74 if __name__ == '__main__':75 import doctest76 doctest.testmod(verbose=True)

On souhaite faire les tests suivants

• tests unitaires: tester si les fonctions factorielle et somme fonctionnent correctement.

• tests d’intégration: tester si les fonctions factorielle et somme fonctionnent correctement ensemble, tester si lafonction coef_binomial fonctionne correctement.

• tests du système complet: tester si la fonction fibonacci donne le bon résultat.

1.5.4 Les outils de tests en Python

Il existe différents outils en Python permettant de réaliser des tests (https://wiki.python.org/moin/PythonTestingToolsTaxonomy).Nous nous intéresserons ici à trois d’entre eux

• doctest

• unittest

• nosetests

74 Chapter 1. Sommaire

Page 79: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

1.5.5 doctest

doctest permet de faire des tests basiques en s’appuyant par exemple sur les docstrings.

Rappel: les docstrings permettent d’écrire de la documentation très facilement directement avec le code source. Ellesse placent tout de suite après une méthode, une fonction, une classe. On rappelle ici brièvement le principe en écrivantune documentation pour une fonction.

def add(a, b):"""Addition de 2 nombres a et b"""return a + b

help(add)

Help on function add in module __main__:

add(a, b)Addition de 2 nombres a et b

doctest effectue

• une recherche dans les sources des bouts de texte qui ressemblent à une session interactive Python,

• une recherche dans des fichiers textes des bouts de texte qui ressemblent à une session interactive Python,

• une exécution de ces bouts de session pour voir si le résultat est conforme.

Les sessions interactives sont représentées par le symbole >>>.

Pour l’utiliser, il suffit d’importer le module doctest et d’appeler testmod si on veut tester l’ensemble d’un modulecomme dans notre exemple fibonacci.py.

Voici un exemple de la sortie:

python fibonacci.py

Trying:coef_binomial(4, 2)

Expecting:6

******************************************************************File ``fibonacci.py'', line 40, in __main__.coef_binomialFailed example:

coef_binomial(4, 2)Expected:

6Got:

6.0Trying:

factorielle(0)Expecting:

1okTrying:

factorielle(5)Expecting:

120okTrying:

1.5. Les tests 75

Page 80: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

fibonacci(10)Expecting:

[1, 1, 2, 3, 5, 8, 13, 21, 34, 55]okTrying:

somme(0, 10, lambda k:k)Expecting:

55.0okTrying:

somme(1, 8, lambda k: 2**k)Expecting:

510.0ok1 items had no tests:

__main__3 items passed all tests:

2 tests in __main__.factorielle1 tests in __main__.fibonacci2 tests in __main__.somme

******************************************************************1 items had failures:

1 of 1 in __main__.coef_binomial6 tests in 5 items.5 passed and 1 failed.

*Test Failed* 1 failures.

Il est également possible d’écrire les tests dans un fichier texte, par exemple au format RST (fibonacci.rst):

1 The example module2 ======================3

4 Using factorial5 -------------------6

7 This is an example text file in reStructuredText format. First import8 factorial from the example module:9

10 >>> from fibonacci import factorielle11

12 Now use it:13

14 >>> factorielle(5)15 120

python -m doctest -v fibonacci.rst

Trying:from fibonacci import factorielle

Expecting nothingokTrying:

factorielle(5)Expecting:

120ok1 items passed all tests:

76 Chapter 1. Sommaire

Page 81: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

2 tests in fibonacci.rst2 tests in 1 items.2 passed and 0 failed.Test passed.

Si doctest est très simple d’utilisation, on se rend bien compte qu’il est assez limité et qu’il ne permet pas de faire destests très élaborés.

Plus de documentation ici: doctest

1.5.6 unittest

Ce module est également appelé PyUnit et reprend l’esprit de JUnit qui permet de faire des tests en java. Il supporte

• les tests automatiques,

• les fonctions d’initialisation et de finalisation pour chaque test,

• l’aggrégation des tests,

• l’indépendance des tests dans le rapport final.

Pour écrire des tests, il faut respecter certaines règles.

• Les tests doivent faire partie d’une classe héritée de la classe unittest.TestCase.

• Les noms des méthodes de cette classe doivent avoir le prefixe test pour être considérés comme tests.

• Les tests sont exécutés par ordre alphabétique.

• La fonction exécutée avant chaque test doit avoir le nom setUp.

• La fonction exécutée après chaque test doit avoir le nom tearDown.

Voici un exemple de son utilisation avec notre module fibonacci.

1 #!/usr/bin/env python2

3 import unittest4 from fibonacci import (factorielle, somme, coef_binomial, fibonacci)5

6

7 class TestFibo(unittest.TestCase):8

9 def test_factorielle_0(self):10 self.assertEqual(factorielle(0), 1)11

12 def test_factorielle_5(self):13 self.assertEqual(factorielle(5), 120)14

15 def test_somme(self):16 self.assertEqual(somme(0, 10, lambda k: k), 55)17

18 def test_coef_binomial(self):19 self.assertEqual(coef_binomial(4, 2), 6)20

21 def test_fibo(self):22 self.assertEqual(fibonacci(10), [1, 1, 2, 3, 5, 8, 13, 21, 34, 55])23

24

1.5. Les tests 77

Page 82: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

25 if __name__ == '__main__':26 unittest.main(verbosity=2) # par defaut verbosity=1

python test_fibonacci.py

test_coef_binomial (__main__.TestFibo) ... oktest_factorielle_0 (__main__.TestFibo) ... oktest_factorielle_5 (__main__.TestFibo) ... oktest_fibo (__main__.TestFibo) ... oktest_somme (__main__.TestFibo) ... ok

----------------------------------------------------------------------Ran 5 tests in 0.001s

OK

Les assertions

Ils permettent de dire à unittest ce que l’on attend comme résultat du test.

• assertEqual: les 2 valeurs doivent être égales.

• assertAlmostEqual: les 2 valeurs doivent être à peu près égales.

• assertTrue: l’expression doit être vraie.

• assertFalse: l’expression doit être fausse.

• ...

1 #!/usr/bin/env python2

3 import unittest4

5

6 class TestAssert(unittest.TestCase):7

8 def test_equal(self):9 self.assertEqual(2, 1 + 1)

10

11 def test_false(self):12 self.assertFalse(1 == 1 + 1)13

14 def test_almostEqual(self):15 self.assertAlmostEqual(0.000011, 0.000012, places=5)16

17

18 if __name__ == '__main__':19 unittest.main(verbosity=2) # par defaut verbosity=1

python test_assert.py

test_almostEqual (__main__.TestAssert) ... oktest_equal (__main__.TestAssert) ... oktest_false (__main__.TestAssert) ... ok

----------------------------------------------------------------------Ran 3 tests in 0.000s

78 Chapter 1. Sommaire

Page 83: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

OK

Rassembler les tests

1 #!/usr/bin/env python2

3 import unittest4

5

6 def allTests():7 from test_assert import TestAssert8 from test_fibonacci import TestFibo9

10 suite = unittest.TestSuite()11 suite.addTest(unittest.makeSuite(TestAssert))12 suite.addTest(unittest.makeSuite(TestFibo))13

14 return suite15

16

17 if __name__ == '__main__':18 unittest.TextTestRunner(verbosity=2).run(allTests())

python all_tests.py

test_almostEqual (test_assert.TestAssert) ... oktest_equal (test_assert.TestAssert) ... oktest_false (test_assert.TestAssert) ... oktest_coef_binomial (test_fibonacci.TestFibo) ... oktest_factorielle_0 (test_fibonacci.TestFibo) ... oktest_factorielle_5 (test_fibonacci.TestFibo) ... oktest_fibo (test_fibonacci.TestFibo) ... oktest_somme (test_fibonacci.TestFibo) ... ok

----------------------------------------------------------------------Ran 8 tests in 0.001s

OK

Plus de documentation ici: unittest

1.5.7 nosetests

Ce module reconnaît automatiquement les tests réalisés à partir de unittest ou de doctest. Il a en plus d’autresfonctionalités intéressantes

• tests de couverture,

• tests de profiling,

• possibilité d’ajouter des plugins,

• ...

1.5. Les tests 79

Page 84: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Exemple d’utilisation avec doctest

nosetests -v --with-doctest fibonacci.py

Doctest: fibonacci.coef_binomial ... okDoctest: fibonacci.factorielle ... okDoctest: fibonacci.fibonacci ... okDoctest: fibonacci.somme ... ok

----------------------------------------------------------------------Ran 4 tests in 0.004s

OK

Exemple d’utilisation avec unittest

nosetests -v test_fibonacci.py

test_coef_binomial (test_fibonacci.TestFibo) ... oktest_factorielle_0 (test_fibonacci.TestFibo) ... oktest_factorielle_5 (test_fibonacci.TestFibo) ... oktest_fibo (test_fibonacci.TestFibo) ... oktest_somme (test_fibonacci.TestFibo) ... ok

----------------------------------------------------------------------Ran 5 tests in 0.001s

OK

Ecriture de tests avec nosetest

nosetests considère qu’un fichier, un répertoire contient des tests si celui-ci satisfait l’expression régulière que l’onappellera dans la suite matchTest

((?:^|[\\b_\\.-])[Tt]est

En d’autres termes, il faut que les noms test ou Test soient au début du nom ou qu’ils soient précédés de - ou _.

La règle s’applique également aux fonctions, classes, ... qui se trouvent dans le fichier à tester.

Exemples

1 #!/usr/bin/env python2

3

4 class test_une_classe:5

6 def pas_untest_valide(self):7 pass8

9 def test_valide(self):10 pass11

12 def encore_un_test_valide(self):13 pass

80 Chapter 1. Sommaire

Page 85: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

14

15

16 def ou_une_fonction_Test():17 pass

nosetests -v test_nose.py

test_nose.test_une_classe.encore_un_test_valide ... oktest_nose.test_une_classe.test_valide ... oktest_nose.ou_une_fonction_Test ... ok

----------------------------------------------------------------------Ran 3 tests in 0.001s

OK

Les assertions

Tout comme unittest, nosetests comprend tout un tas d’outils pour faire des assertions. Ils se trouvent dansnose.tools.

Attention: contrairement à unittest, nosetests satisfait les règles de la PEP 8. Par conséquent, assertEqual devientassert_equal.

Initialisation et finalisation des tests

Il est possible d’exécuter du code en début et en fin de tests comme avec les fonctions setUp et tearDown deunittest.

Pour les packages de tests

On peut ajouter les fonctions d’initialisation et de finalisation dans le fichier __init__.py.

Les fonctions d’initialisation doivent se nommer setup, setup_package, setUp ou setUpPackage.

Les fonctions de finalisation doivent se nommer teardown, teardown_package, tearDown outearDownPackage.

Pour les modules de tests

Un module de tests est un module dont le nom satisfait matchTest.

De la même manière que pour les packages, les fonctions d’initialisation et de finalisation doivent avoir les nomssetup, setup_module, setUp ou setUpModule et teardown, teardown_module, tearDown outearDownModule

Pour les classes de tests

Une classe de tests est une classe dont le nom satisfait matchTest. Elle doit se trouver dans un module de tests.

Soit elle dérive de la classe unittest.TestCase, soit elle comporte des méthodes qui satisfont le matchTest.

Les fonctions d’initialisation sont setup_class, setupClass, setUpClass, setupAll ou setUpAll.

1.5. Les tests 81

Page 86: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Les fonctions de finalisation sont teardown_class, teardownClass, tearDownClass, teardownAll outearDownAll.

Pour les fonctions de tests

Une fonction de tests est une fonction dont le nom satisfait matchTest. Elle doit se trouver dans un module de tests.

Contrairement aux précédents cas, il n’y a pas de format particulier pour les phases d’initialisation et de finalisation.

Il faut utiliser le décorateur with_setup qui se trouve dans le module nose.

1 #!/usr/bin/env python2

3 from nose import with_setup4

5

6 def init_func():7 print("j'initialise !!")8

9

10 def end_func():11 print("je finalise !!")12

13

14 @with_setup(init_func, end_func)15 def test1():16 print("test 1")

nosetests -s test_nose2.py

j'initialise !!test 1je finalise !!.----------------------------------------------------------------------Ran 1 test in 0.000s

OK

Les attributs

Dans nosetests, il est possible de sélectionner une partie des tests en utilisant des attributs.

On peut par exemple exécuter que les tests qui ne sont pas lents.

1 #!/usr/bin/env python2

3 from nose.plugins.attrib import attr4

5

6 @attr('lent')7 def test_lent():8 print('test lent')9

10

11 def test_rapide():12 print('test rapide')

82 Chapter 1. Sommaire

Page 87: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

nosetests -s test_nose_attr.py

test lent.test rapide.----------------------------------------------------------------------Ran 2 tests in 0.000s

OK

nosetests -s -a '!lent' test_nose_attr.py

test rapide.----------------------------------------------------------------------Ran 1 test in 0.000s

OK

1 #!/usr/bin/env python2

3 from nose.plugins.attrib import attr4

5

6 @attr(vitesse='lent')7 def test_lent():8 print('test lent')9

10

11 @attr(vitesse='rapide')12 def test_rapide():13 print('test rapide')

nosetests -s -a vitesse='lent' test_nose_attr.py

test lent.----------------------------------------------------------------------Ran 1 test in 0.000s

OK

Les tests de couverture

Il est également possible avec nosetests de voir si nos tests passent bien sur l’ensemble de notre code.

nosetests --with-coverage --cover-package=fibonacci test_fibo.py

.....Name Stmts Miss Cover Missing-----------------------------------------fibonacci.py 23 2 91% 66-67----------------------------------------------------------------------Ran 5 tests in 0.002s

OK

1.5. Les tests 83

Page 88: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

On voit qu’on a oublié de tester 2 lignes de notre module. Si on creuse un peu ces 2 lignes correspondent aux lignesdu main ce qui n’est donc pas très important.

1.5.8 Exercices

Nous allons utiliser les outils vus dans le cours (doctest, unittest et nosetests) sur un package permettant de simulerune calculatrice.

Il faut récupérer les sources qui se trouvent dans tests/tests_squelette. Pour travailler sur le projet sansl’installer, nous allons utiliser la commande pip.

cd tests/tests_squelettepip install -e .

Vous avez alors un exécutable qui s’appelle calc.py

calc.py

usage=====

./calc.py s

où s est une chaine de caractères représentant l'expression àcalculer.

calc.py '3+4-5'

2.0

Ce package contient trois modules

• operateur: ce module explique ce que fait une addition, une soustraction, ...

• parser: ce module permet de parser la chaîne de caractères.

• calculatrice: ce module permet de faire fonctionner la calculatrice en fonction de la chaîne de caractères entréepar l’utilisateur.

Lorsque l’on écrit un package en Python, on suit généralement l’arborescence suivante pour les tests.

84 Chapter 1. Sommaire

Page 89: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

1. Reprendre les modules operateur et parser et ajouter des tests en utilisant doctest.

2. Créer un répertoire de tests et écrire des tests utilisant unittest

3. Exécuter les tests créés précedemment avec nosetests

4. Ecrire des tests ayant le matchTest de nosetests dans le répertoire tests.

5. Ajouter des attributs et tester.

6. Faire des tests de couverture et rajouter des tests si nécessaire.

1.6 Projet BallPack

Vous allez à présent écrire un projet de A à Z en utilisant tout ce que vous avez vu pendant ces 5 demi journées.

Le projet proposé est l’écriture d’un package permettant de représenter des balles qui se déplacent dans un carré et quirebondissent sur les bords. On utilisera Tkinter pour l’interface graphique car il est fourni de base avec Python mais ily a aujourd’hui beaucoup mieux

• PySide

• PyQt

• Kivy

Les balles pourront se déplacer de différentes manières:

• à une vitesse constante,

• avec une force de gravité,

• avec une fonction proposée par l’utilisateur.

1.6. Projet BallPack 85

Page 90: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

L’arborescence du projet final devra ressembler à

Voici également une vue de l’interface graphique

86 Chapter 1. Sommaire

Page 91: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Nous allons commencer par mettre en place le virtualenv, ensuite on implémentera les balles et enfin on créera ladocumentation du projet.

Récuperez ballPack_squelette pour commencer ce projet.

1.6.1 Création du virtualenv

Initialisation

Créer un répertoire projet dans lequel vous mettrez le projet (dans le répertoire ballPack à partir du squelette=) ainsique le virtualenv (dans le répertoire env).

Entrer dans le virtualenv pour la suite des questions.

Installation des dépendances

Notre projet dépend de plusieurs paquets (ipython, sphinx, tikitiki), installez-les dans le virtualenv.

1.6. Projet BallPack 87

Page 92: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Dans un virtualenv, vous pouvez obtenir la liste des dépendances installées.

pip freeze

1 ipython==4.0.02 Sphinx==1.3.13 tikitiki==0.2

Du coup, vous pouvez facilement le sauvegarder dans un fichier:

pip freeze > requirements.txt

Et vous en servir pour mettre à jour votre virtualenv:

pip install --upgrade --requirement requirements.txt

1.6.2 Le module ballMod.py

Une balle, qu’elle soit à vitesse constante, avec une force de gravité, ..., a toujours les mêmes attributs.

• coords: liste des coordonnées du centre de la balle

• v: vecteur vitesse de la balle

• radius: rayon de la balle

• domain: liste de liste comprenant les dimensions du domaine [[xmin, xmax], [ymin, ymax]]

• color: la couleur de la balle

Question 1

Ecrivez une classe Ball qui sera la classe mère. Voici la documentation de sa méthode __init__

"""Initialisation de la classe Ball

:param x: coordonnée du centre de la balle suivant x:param y: coordonnée du centre de la balle suivant y:param vx: vitesse de la balle suivant x (défaut: 1):param vy: vitesse de la balle suivant y (défaut: 1):param radius: rayon de la balle (défaut: 20):param xdomain: domaine de la balle suivant x (défaut: [0, 800]):param ydomain: domaine de la balle suivant y (défaut: [0, 600]):param color: couleur de la balle (défaut: "green")"""

Déduisez en son implantation.

Question 2

Ecrivez une méthode check_velocity qui ne prend pas de paramètre et qui vérifie si la balle ne sort pas dudomaine pour chacune des directions.

Si elle sort, la méthode

• remet le centre de la balle à l’intérieur (on prendra les bords du domaine plus ou moins le rayon),

• inverse le sens de la vitesse concernée,

88 Chapter 1. Sommaire

Page 93: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

• renvoie True.

Sinon, elle renvoie False.

Question 3

Ecrivez une méthode qui permet d’avoir l’affichage suivant lorsque l’on fait un print d’une balle

Ball:coord : [1, 1]velocity : [1, 1]radius : 20color : greendomain : [[0, 800], [0, 600]]

Nous allons maintenant créer trois classes filles. Pour chacune d’elles, nous allons implanter la méthode move per-mettant de déplacer la balle au cours du temps.

Question 4

Ecrivez une classe BouncingBall qui hérite de la classe Ball et qui fait juste rebondir la balle sur les bords. Saméthode move est très simple

• on change les coordonnées de la manière suivante

x = x + vxy = y + vy

• on regarde si les coordonnées ne sortent pas du domaine et on les modifie si nécessaire.

Question 5

Ecrivez une classe GravityBall qui hérite de la classe Ball et où la vitesse y est soumise à la gravité. De plus,dès que la balle touche un bord, elle est amortie. Elle a besoin de différents paramètres que vous pourrez mettredirectement dans la méthode

• ∆t = 0.1

• g = 9.81

• ca = 0.9

Sa méhode move est

• on change les coordonnées de la manière suivante

vy = vy − ∆t ∗ gx = x + ∆t ∗ vxy = y − ∆t ∗ vy

• on regarde si les coordonnées ne sortent pas du domaine et on les modifie si nécessaire.

• si on est sorti du domaine, on amortie les vitesses

vx = ca ∗ vxvy = ca ∗ vy

1.6. Projet BallPack 89

Page 94: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Question 6

Ecrivez le fichier setup.py permettant d’installer le package ballPack avec le module ballMod.

Question 7

Ecrivez des tests sur les classes précédemment créées.

1.6.3 Le module color.py

Dans ce module, nous allons créer une classe Color qui prend en paramètre un fichier contenant des noms de couleurset qui les stocke dans un attribut colorNames qui est de type list.

Question 1

Ecrivez la méthode ___init__ dont la documentation est

""":param filename: nom du fichier contenant les couleurs (défaut: None)Si None, on lit le fichier 'data/rgb.txt' se trouvant dans ballPack."""

On utilisera la méthode os.path.dirname pour retrouver le chemin du fichier data/rgb.txt une fois le mod-ule installé.

Question 2

Ecrivez une méthode get_random_color qui renvoie de manière aléatoire une couleur de la liste colorNames.On utilisera la méthode choice du module random.

Question 3

Modifiez le setup.py pour avoir ce module et le fichier data/rgb.txt installé.

1.6.4 Le script tkgui.py

Question 1

Modifiez le fichier setup.py pour que le script script/tkgui.py soit installé.

Question 2

Exécutez ce script et corrigez votre package pour que celui-ci fonctionne.

1.6.5 Le module save.py

Nous allons à présent faire en sorte de pouvoir sauvegarder et recharger un état au format CSV. On se servira dumodule ‘csv <https://docs.python.org/3/library/csv.html>‘__ qui est de base dans Python.

90 Chapter 1. Sommaire

Page 95: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

Question 1

Ecrivez une fonction save_balls dont la documentation est

"""sauvegarde d'une liste de balles au format csv.

:param balls: liste à sauvegarder:param filename: fichier de la sauvegarde:param delimiter: délimiteur entre chaque entrées (défaut: ',')"""

Question 2

Ecrivez une fonction read_balls dont la documentation est

"""lit un fichier csv contenant une liste de balles etrenvoie cette liste en les contruisant.

:param filename: fichier de la sauvegarde:param delimiter: délimiteur entre chaque entrées (défaut: ','):return: liste de balles"""

Question 3

Décommentez les lignes de la méthode saveAndLoadState dans tkgui.py, réinstallez le package et testez.

1.6.6 Ajout d’une classe UserBall

Ajoutez une classe UserBall qui permet de déplacer une balle selon une fonction et ses paramètres donnés enparamètre de la fonction move. Puis testez.

1.6.7 Documentation du projet

Il est possible de créer de la documentation à partir des commentaires dans le code de notre projet.

pip install Sphinxsphinx-quickstart

Il faudra s’assurer de bien activer l’extension autodoc. Une fois la structure de base créée, vous pourrez créer ladocumentation en html avec:

make html

1.7 Documentations

Voici quelques liens utiles:

• PEP 8

• Python

1.7. Documentations 91

Page 96: Formation Python 3...Formation Python 3, Release 2015.12 Il s’agit d’une formation de base à Python. La même formation sera jouée dans les différentes régions, par des intervenants

Formation Python 3, Release 2015.12

• Sphinx

92 Chapter 1. Sommaire