Débuter en Python
module assuré par Matias Guijarro
email:
guijarro@esrf.fr
Grenoble, France
Introduction
Historique du langage Python
Caractéristiques essentielles
Différentes implémentations de Python
1
Présentation du langage
2
3
Installation
Premiers pas
Problématiques liées à Python
Utilisation d'une distribution de Python
Gestion d'environnements
Eléments de base du langage
Exceptions
Built-in Super Heroes
Paquets et modules
1. Présentation du langage
2. Installation
3. Premiers pas
Introduction
#4 au classement TIOBE (Août 2018)
#1 classement IEEE
Plus grande progression sur StackOverflow, numéro 1
1. Présentation du langage
2. Installation
3. Premiers pas
Historique du langage Python
Introduction
janvier 1994
version 1.0
ajout de lambda, map, filter, reduce
(inspiré de Lisp)
février 1991
version 0.9.0
publication du code sur alt.sources (newsgroup)
octobre 1996
version 1.4
ajout des keyword arguments,
nombres complexes,
membres de classe "privés"
avril 2001
version 2.1
list comprehensions (inspiré de Haskell), imbrication de la portée des variables, création de la Python Software Foundation
générateurs, unification des types: langage objet complet
version 2.2
décembre 2001
septembre 2006
version 2.5
Gestion de contexte (mot-clef "with")
décembre 2008
version 3.0
Ré-écriture complète, perte de la compatibilité descendante
Dernière de la série 2
version 2.7
juillet 2010
mars 2014
version 3.4
ajout d'asyncio (concurrence d'entrées/sorties sur un seul thread)
juin 2018
version 3.7
Auteur principal: Guido Van Rossum
1. Présentation du langage
2. Installation
3. Premiers pas
Caractéristiques essentielles
Introduction
Langage multi-paradigme
impératif, structuré, fonctionnel, objet
Langage interprété
VM (bytecodes), pas de compilation
Typage dynamique fort
Duck-typing, types objets
Lisibilité du code
Syntaxe épurée, indentation obligatoire
"Batteries included"
Librairie standard très complète
Ramasse-miettes (GC)
Gestion de mémoire automatique
1. Présentation du langage
2. Installation
3. Premiers pas
Différentes implémentations de Python
Introduction
Interpréteur Python écrit en Java, s'intègre à la JVM, permet l'interopérabilité entre Java et Python (depuis 1997)
Interpréteur Python écrit en C#, s'intègre au framework Microsoft .NET (depuis 2006)
Interpréteur Python écrit en... Python, qui s'exécute à travers un compilateur Just-In-Time (depuis 2008)
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Problématiques liées à Python
- De multiples versions de Python existent (Python 2, Python 3, Jython, Pypy, etc.)
- Différents projets peuvent nécessiter différentes versions
- On ne peut pas toujours utiliser le Python fourni par le système
- Mise à jour impossible
- Package(s) manquant(s)
- Gestion des dépendances compliquée
- Les modules Python compilés (en C, C++) peuvent nécessiter des librairies à installer dans le système
- Conflits potentiels à gérer
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Utilisation d'une distribution de Python
Indépendante du système, pas de conflits entre versions de packages Python, utilisable sans privilèges utilisateur spécifiques
Permet de gérer plusieurs environnements, pour rassembler toutes les dépendances d'un projet dans un même contexte
Certaines distribution de Python sont basées sur un package manager complet, pouvant permettre l'installation d'autres logiciels
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Utilisation d'une distribution de Python
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Gestion d'environnements
Création | conda create -n nouvel_env python=3 |
Activation | Depuis Linux: conda activate nouvel_env |
Liste des packages |
conda list (depuis un environnement actif) Vers un fichier: conda list --explicit >fichier.txt |
Clonage | conda create --clone source_env --name nouvel_env |
Supprimer | conda env remove --name nom_env |
Installer un paquet |
conda install nom_paquet Exemples: > conda install numpy > conda install git |
Lister les environnements | conda env list |
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Installer Jupyter
conda create -n turtle python=3
conda activate turtle
conda install -c conda-forge notebook
jupyter notebook
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Python REPL
(Read-Eval-Print Loop)
L'interpréteur Python, démarré sans arguments, propose une invite de commande en mode interactif
L'interpréteur attend une ligne en entrée, l'évalue et affiche le résultat de cette évaluation:
matias@kashyyyk ~ $ python
Python 3.7.0 (default, Jun 28 2018, 13:15:42)
[GCC 7.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> 1+2
3
>>> print("Hello, world !")
Hello, world !
>>>
matias@kashyyyk ~ $
< [CTRL]+[D] permet de quitter l'interpréteur
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Interpréter un fichier
et revenir au mode interactif
matias@kashyyyk ~ $ cat test.py
a = 5
print("Hello, world !")
matias@kashyyyk ~ $ python -i test.py
Hello, world !
>>> a
5
>>>
L'option de ligne de commande -i permet d'interpréter un fichier et de revenir au mode interactif: les variables et fonctions définies restent disponibles
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Eléments de base du langage
- Arithmétique: +, -, *, /, //, %, **
- Programmation conditionnelle: if, else, elif
- Types de données: int, float, complex, strings, (), [], {}, {:}
- Objet "vide" (absence de valeur): None
- Boucles: for, while
- Modules: import
- Gestion d'erreurs par exceptions: try...except
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Orientation Objet
-
Tout est objet en Python
- chaque objet est référencé (refcount)
- chaque objet a un type de base (classe)
tout code Python doit être orienté objet
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Variables et espaces de noms
Les variables n'ont pas besoin d'être déclarées
On affecte un objet à une variable en utilisant le signe =
Le type des variables est celui de leur valeur
Les variables sont donc des références d'objet, qui lient un nom avec un objet dans un espace de nom (namespace)
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Variables et espaces de noms
Namespace des built-ins du langage: print, range, open...
Module: namespace global
Fonction: namespace local
- Chaque fonction créé un espace de nom local
- Les fonctions peuvent être imbriquées
Résolution de nom vers le namespace plus global
La portée des variables dépend des espaces de noms
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Définir une fonction: le mot-clef 'def'
Le mot-clef return permet de retourner une valeur (optionnel)
def nom_de_la_fonction(argument1, ..., argumentN):
# indentation de début de bloc
Arguments:
- On peut donner des valeurs par défaut aux arguments
- La notation * permet de spécifier une liste d'arguments variables
- La notation ** permet de spécifier un dictionnaire d'arguments variables nommés
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exemples de fonctions
# exemple de fonction avec 2 arguments obligatoires x et y
def addition(x, y):
# entrée dans le bloc de la fonction:
# indentation obligatoire
#
# la fonction définit un namespace local,
# la portée des variables x et y ne dépasse
# pas la fonction
return x+y
# exemple de fonction avec 2 arguments obligatoires
# et un par défaut
def creer_point(x, y, z=0):
# retour de valeurs multiples
return x, y, z
# appel de fonction
>>> creer_point(1, 2)
(1, 2, 0)
>>> creer_point(-1, 2, 3)
(-1, 2, 3)
# exemple de procédure
# (fonction sans valeur de retour)
def afficher_bonjour(nom, prenom):
print("Bonjour, "+prenom+" "+nom)
# pas de return: la fonction renvoie
# None par défaut
# exemple d'arguments variables
def compter_amis(*amis):
# 'amis' reçoit la liste des arguments fournis
return len(amis) # len renvoie la taille d'une liste
>>> compter_amis("Patrick", "Gérard", "Noémie")
3
# exemple d'arguments variables nommés
def afficher_age_amis(**age_amis):
# age_amis reçoit le dictionnaire des arguments
# fournis: { nom_argument: valeur }
for ami, age in age_amis.items():
print(ami.title()+" a "+str(age)+" ans.")
>>> afficher_age_amis(patrick=38, gerard=60, noemie=27)
Patrick a 38 ans.
Gerard a 60 ans.
Noemie a 27 ans.
Blocs délimités par l'indentation:
Utiliser un éditeur de code qui remplace [Tab] par des espaces,
configurer pour avoir 4 espaces par [Tab]
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Entrées / Sorties
Réaliser une saisie: fonction input
>>> n = input("Quelle est la réponse ? ")
Quelle est la réponse ?
L'exécution attend la saisie de l'utilisateur, terminée par [Entrée]
La valeur renvoyée par input est toujours de type string (chaîne de caractères)
Flux standards (stdin, stdout, stderr)
Afficher un texte: fonction print
>>> print("Hello, world !")
Hello, world !
>>> import sys
>>> print("Hello to stderr", file=sys.stderr)
Hello to stderr
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Entrées / Sorties
open permet d'ouvrir un fichier en lecture ou en écriture
dans un fichier
>>> f = open("/etc/issue", "r")
>>> print(f.read())
Linux Mint 17.2 Rafaela \n \l
>>>
Caractère | Description |
---|---|
r | Lecture (depuis le début) - par défaut |
w | Ecriture (fichier existant écrasé) |
a | Ajouter (depuis la fin) |
b | binaire |
t | texte - par défaut |
Le mode d'accès est spécifié par une combinaison de caractères
.read(): lit l'intégralité du fichier
.readline(): lit une ligne
.write(s): écrit la chaîne s
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
La Tortue
Module inspiré de la "tortue graphique" (turtle) du langage Logo
Permet de dessiner en utilisant une table traçante virtuelle
La documentation officielle de Python explique en détails les fonctions du module turtle : suivre ce lien
Installation sous Jupyter notebook
et redémarrer: jupyter notebook
conda install notebook -c conda-forge
pip install mobilechelonian,
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice T1:
Continuer le script suivant pour écrire une fonction "marche" qui dessine une marche d'escalier, puis une fonction "escalier" qui dessine un nombre de marches donné en paramètres
from turtle import * # ou bien: from mobilechelonian import Turtle sous Jupyter
t = Turtle()
t.speed(5) #parametrage de la vitesse de 1 lent à 10 rapide, 0 étant la vitesse la plus rapide
t.shape("turtle") #choix de la forme de la tortue
t.pencolor("red") #choix de la couleur du crayon
t.pensize(4) #épaisseur du crayon
t.up() #lever le crayon
t.goto(0,0) #aller à la position (0,0)
t.setheading(0) #orientation de la tortue vers l'Est / 90 Nord / 180 Ouest / 270 Sud
t.down() #poser le crayon
50 pixels
Indication: en Python normal (pas Jupyter), la fonction "turtle.mainloop" permet de conserver la fenêtre graphique à l'écran à l'issue du tracé
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Solution de l'exercice T1:
from turtle import *
speed(5) #parametrage de la vitesse de 1 lent à 10 rapide, 0 étant la vitesse la plus rapide
shape("turtle") #choix de la forme de la tortue
pencolor("red") #choix de la couleur du crayon
pensize(4) #épaisseur du crayon
up() #lever le crayon
goto(0,0) #aller à la position (0,0)
setheading(0) #orientation de la tortue vers l'Est / 90 Nord / 180 Ouest / 270 Sud
down() #poser le crayon
def marche():
left(90)
forward(50)
right(90)
forward(50)
def escalier(n):
for i in range(n):
marche()
escalier(5)
mainloop()
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice T2:
Ecrire la fonction "polygone" qui dessine un polygone régulier de N côtés
avec N=6
Exemple:
La fonction doit prendre un argument optionnel "longueur" avec une valeur par défaut de 50 pixels
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Solution de l'exercice T2
def polygone(n, longueur=50):
pendown()
angle = 360/n
for i in range(n):
forward(longueur)
right(angle)
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice T3: l'horloge
Ecrire une fonction "horloge" qui affiche une horloge avec le mouvement de l'aiguille des secondes (trotteuse), prenant en paramètre le rayon de l'horloge en pixels (valeur par défaut: 100 pixels)
Indications:
- Pour faire une animation il suffit d'effacer le dessin existant en repassant en blanc et d'en faire un autre...
- Le module "datetime" fournit les données relatives au temps
- Le module "time" possède une fonction "sleep(X)" pour attendre X secondes
- Utiliser des fonctions imbriquées (= fonctions dans une fonction) pour dessiner le cadran, dessiner l'aiguille, effacer l'aiguille, etc.
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Solution de l'exercice T3
import time
import datetime
from turtle import *
shape("arrow")
pensize(4)
delay(0)
home()
def horloge(taille_cadran=100):
def dessiner_cadran():
angle = 360/12
penup()
for i in range(12):
right(angle)
forward(taille_cadran)
pendown()
dot(taille_cadran/20, "blue")
penup()
backward(taille_cadran)
def dessiner_trotteuse(s):
angle = 360/60
setheading(90-(s*angle))
color("red")
forward(taille_cadran*0.8)
def effacer_trotteuse():
color("white")
backward(taille_cadran*0.8)
dessiner_cadran()
pendown()
while True:
now = datetime.datetime.now()
dessiner_trotteuse(now.second)
time.sleep(1) # pause de 1 seconde
effacer_trotteuse()
horloge(200)
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice 1
Ecrire le programme qui calcule la factorielle d'un nombre entier positif saisi par l'utilisateur
factorielle(n) = n*(n-1)*(n-2)*...*1, notation mathématique: n!
A savoir: 0! = 1
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Solution de l'exercice 1
>>> def fact(n):
if n == 0:
return 1
else:
return n * fact(n-1)
>>> a = input("Veuillez saisir un nombre entier positif: ")
>>> print(fact(int(a)))
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice 2
Ecrire la fonction qui extrait et affiche la n-ième fortune du fichier /usr/share/games/fortunes/fortunes
Les fortunes sont délimitées par une ligne contenant la chaîne de caractères "%\n"
Les fortunes peuvent occuper plusieurs lignes
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Solution de l'exercice 2
def fortune(n):
with open("/usr/share/games/fortunes/fortunes") as f:
i = 1
while i < n:
if f.readline() == '%\n':
i += 1
l = f.readline()
while l != '%\n':
print(l)
l = f.readline()
>>> fortune(10)
Accent on helpful side of your nature. Drain the moat.
>>>
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Gestion d'erreur par exceptions
Python 3.7.0 (default, Jun 28 2018, 13:15:42)
[GCC 7.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> bla
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
NameError: name 'bla' is not defined
>>> 1/0
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
ZeroDivisionError: integer division or modulo by zero
>>> try:
... 1/0
... except ZeroDivisionError:
... print("Désolé: opération impossible.")
...
Désolé: opération impossible.
>>>
Lorsqu'une erreur se produit, Python génère une exception qui interrompt l'exécution en cours
< try...except permet d'attraper les exceptions, pour rétablir l'exécution normale
>
le type d'exception renseigne sur la nature du problème
< la trace rappelle le contexte dans lequel l'erreur s'est produite
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Approche optimiste du traitement des erreurs
On essaie le cas général, on traite éventuellement les exceptions
"EAFP": Easier to Ask Forgiveness than Permission
import os
# ne correspond pas au style de codage EAFP
if os.path.exists("file.txt"):
os.unlink("file.txt")
import os
try:
os.unlink("file.txt")
# OSError est levée si le fichier n'existe pas
except OSError:
# on ignore l'erreur, dans ce cas
pass
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Levée d'exception
Le mot-clef raise permet de générer une exception dans son propre code
# calcul du périmètre d'un cercle,
# le rayon ne doit pas être négatif
def périmètre(rayon):
if rayon < 0:
raise ValueError("Le rayon du cercle est négatif")
return 2*rayon*math.pi
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Masquer les exceptions
A moins de bien savoir, masquer les exceptions s'effectue en utilisant la classe Exception
try:
...
except Exception as e:
if isinstance(e, ZeroDivisionError):
# division par zero
elif isinstance(e, AttributeError):
# attribut manquant
...
# l'exécution du code continuera toujours ici ensuite
# (à moins que le code plus haut ne fasse un return...)
La clause except: utilisée sans spécifier de type d'exception rattrape TOUTES les exceptions (y compris KeyboardInterrupt, par exemple)
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Clauses "else" et "finally"
Le schéma classique try...except: accepte une clause else: qui est exécutée quand il n'y a pas d'erreur
Enfin, la clause finally: est toujours exécutée (y compris en cas d'exception dans le traitement de l'exception)
Cela est particulièrement utile pour libérer une ressource (lock, fermeture de fichier, ...)
try:
... #code pouvant générer une exception
except Exception:
... #code de traitement des exceptions
else:
... #code exécuté s'il n'y a pas eu d'exception
finally:
... #code TOUJOURS exécuté à la fin
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Built-ins Python
Python 3.7.0 (default, Jun 28 2018, 13:15:42)
[GCC 7.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import builtins
>>> dir(builtins)
['ArithmeticError', 'AssertionError', 'AttributeError', 'BaseException', 'BlockingIOError', 'BrokenPipeError',
'BufferError', 'BytesWarning', 'ChildProcessError', 'ConnectionAbortedError', 'ConnectionError', 'ConnectionRefusedError',
'ConnectionResetError', 'DeprecationWarning', 'EOFError', 'Ellipsis', 'EnvironmentError', 'Exception',
'False', 'FileExistsError', 'FileNotFoundError', 'FloatingPointError', 'FutureWarning', 'GeneratorExit', 'IOError',
'ImportError', 'ImportWarning', 'IndentationError', 'IndexError', 'InterruptedError', 'IsADirectoryError', 'KeyError',
'KeyboardInterrupt', 'LookupError', 'MemoryError', 'ModuleNotFoundError', 'NameError', 'None', 'NotADirectoryError',
'NotImplemented', 'NotImplementedError', 'OSError', 'OverflowError', 'PendingDeprecationWarning', 'PermissionError',
'ProcessLookupError', 'RecursionError', 'ReferenceError', 'ResourceWarning', 'RuntimeError', 'RuntimeWarning',
'StopAsyncIteration', 'StopIteration', 'SyntaxError', 'SyntaxWarning', 'SystemError', 'SystemExit', 'TabError',
'TimeoutError', 'True', 'TypeError', 'UnboundLocalError', 'UnicodeDecodeError', 'UnicodeEncodeError', 'UnicodeError',
'UnicodeTranslateError', 'UnicodeWarning', 'UserWarning', 'ValueError', 'Warning', 'ZeroDivisionError',
'__build_class__',
'__debug__',
'__doc__',
'__import__',
'__loader__',
'__name__',
'__package__',
'__spec__',
'abs', 'all', 'any', 'ascii', 'bin', 'bool', 'breakpoint', 'bytearray', 'bytes', 'callable', 'chr', 'classmethod',
'compile', 'complex', 'delattr', 'dict', 'dir', 'divmod', 'enumerate', 'eval', 'exec', 'exit', 'filter', 'float',
'format', 'frozenset', 'getattr', 'globals', 'hasattr', 'hash', 'help', 'hex', 'id', 'input', 'int', 'isinstance',
'issubclass', 'iter', 'len', 'list', 'locals', 'map', 'max', 'memoryview', 'min', 'next', 'object', 'oct', 'open',
'ord', 'pow', 'print', 'property', 'quit', 'range', 'repr', 'reversed', 'round', 'set', 'setattr', 'slice', 'sorted',
'staticmethod', 'str', 'sum', 'super', 'tuple', 'type', 'vars', 'zip']
>>>
Exceptions standard
Fonctions
Connaître l'essentiel des fonctions standard du langage (et à quoi elles servent !) et les exceptions les plus courantes par coeur est un atout
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
int
float
Entier signé, 64 bits minimum
Taille maximum infinie, limité à la mémoire disponible
Décimal signé, 64 bits minimum
(voir sys.float_info)
>>> n = 26 # == 0x1A, == 032, == int('26')
>>> 1234567**89
13957418598822621635241167796707938465481984
07702631541489010157114345875559162218718550
53939370772085656915237689603767083349991793
71334647109157262849410607614641938921108745
92091708239393326778590937567344701723518950
79430772488109105692648444480028380122417140
93256943282431643000874095802505371673542134
47294105206815597154794725416313214250137689
78692403188995380725532383634472359562908542
46954797114645706242235684570157179581172114
61266397348099045779670126089615289970121785
37266420111446716001493476975934877110973383
995456863730247
>>> f = 26.4 # == 2.64E1 == float('26.4')
>>> import sys
>>> sys.float_info
sys.float_info(max=1.7976931348623157e+308,
max_exp=1024, max_exp=308,
min=2.2250738585072014e-308,
min_exp=-1021, min_10_exp=-307, dig=15,
mant_dig=53, epsilon=2.220446049250313e-16,
radix=2, rounds=1)
>>> 0.9999999999999999 #plus de 15 chiffres
1.0
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
str, bytes
Chaînes de caractères
s1 = 'Hello'
s2 = 'β is b in greek' # une string Python peut contenir des caractères Unicode
s3 = '12'
s3 == str(12)
Les chaînes de caractères Python sont immutables
>>> s='ABC'
>>> s[2]='*'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'str' object does not support item assignment
>>>
b1 = b':)' # représentation de l'entier 14889 (codée sur 2 bytes; Big-Endian)
b1 == bytes((58,41))
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
[ ]
Conteneurs:
liste
Séquence ordonnée mutable
>>> l1 = [1, 2.5, None, "hello"]
>>> l1[0] == 1
True
>>> l1[-1] == "hello"
True
>>> l1.index(None) == 2
True
>>> del l1[2]
>>> len(l1) == 3
True
>>>
# créer une liste de 1000 zéros
l2 = [0]*1000
# créer une liste issue d'une séquence
# de caractères
l3 = list("hello")
l3 == ["h", "e", "l", "l", "o"]
# créer une suite avec "range()"
l4 = range(10)
l4 == [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
( )
Conteneurs:
tuple (n-uplet)
Séquence ordonnée immutable
>>> t1 = ("Pierre", "Martin", 24)
>>> nom, prenom, age = t1 # dégroupage
>>> t1[0] == prenom == "Pierre"
True
>>> t1[-1] == 24
True
>>> prenom, nom = nom, prenom # permutation
>>> prenom == "Martin"
True
>>> del t1[2]
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'tuple' object doesn't support item deletion
>>>
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
{ }
Conteneurs:
set
Ensemble d'éléments uniques non-ordonné, mutable
>>> filles = set(('Julie', 'Alice'))
>>> garçons = set(('Romain', 'Pierre'))
>>> personnes = filles | garçons # '|': opérateur d'union
>>> personnes
{'Romain', 'Julie', 'Alice', 'Pierre'}
>>> vegetariens = set(('Pierre', 'Julie'))
>>> filles_vegetariennes = filles.intersection(vegetariens)
>>> filles_vegetariennes
{'Julie'}
>>> personnes_qui_mangent_de_la_viande = personnes - vegetariens
>>> personnes_qui_mangent_de_la_viande
{'Romain', 'Alice'}
>>>
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
{:}
Conteneurs:
dict
"map", "dictionnaire": association d'une clef et d'une valeur ; mutable
>>> d = { "a": 5, "b": 4, "toto": [1,2,3], 8: "hello" }
>>> d["a"] == 5
>>> d[8] == "hello"
>>> list(d.keys())
['a', 'b', 'toto', 8]
>>> list(d.values())
[5, 4, [1, 2, 3], 'hello']
>>> del d["b"]
>>> len(d) == 3
True
< depuis Python 3.7, l'ordre d'insertion des données dans un dict est préservé pour le parcours des clefs ou des valeurs
non-ordonné avant Python 3.7
Modern dictionaries: présentation de R. Hettinger
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
bool
Vrai / Faux logique
b1 = True # == 1
b2 = False # == 0
bool | True | False |
---|---|---|
0 | ||
1234 | ||
-10 | ||
"False" | ||
"" | ||
None | ||
() | ||
[] | ||
{} | ||
[1, 6, 9] |
Tout type de donnée ayant une valeur "vide" est Faux
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Opération utiles sur les chaînes de caractères
>>> s=" Hello, world ! "
>>> s.lower() # conversion en minuscules
" hello, world ! "
>>> s.upper() # conversion en majuscules
" HELLO, WORLD ! "
>>> s.split(", ") # renvoie une liste, en découpant la string suivant le délimiteur spécifié
[" Hello", "world ! "]
>>> "-".join(["a","b"]) # concaténer les éléments d'un itérable
"a-b"
>>> s.replace(" !", ".") # remplacer une sous-chaîne par une autre
" Hello, world. "
>>> s.strip() # supprimer les espaces avant et après la chaîne
"Hello, world !"
Formatage et templating
>>> s = "Je m'appelle {} {}.".format("Matias", "Guijarro")
>>> print(s)
Je m'appelle Matias Guijarro.
>>> name = "Matias"
>>> s = f"Je m'appelle {name}" # nouveau dans Python 3.6: f-strings
>>> print(s)
Je m'appelle Matias
>>> a, b = 3, 5
>>> s = f"{a} + {b} = {a+b}"
>>> print(s)
3 + 5 = 8
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
while
Boucle simple:
Exécute le code dans le bloc tant que la condition est vraie
>>> i = 0
>>> while i < 5:
print(i)
i += 1
0
1
2
3
4
>>>
Le mot-clef break permet de sortir d'une boucle sans que la condition ne soit évaluée
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
for
Boucle d'itération
>>> for item in container:
...
>>> for i, item in enumerate(container):
# i est l'index de l'item dans le container
...
>>> for item1, item2 in zip(container1, container2):
# item1 est le n-ième item de container1
# item2 est le n-ième item de container2
# (item1 et item2 doivent avoir la même longueur)
...
>>> for item in reversed(container):
# les items sont retournés en commençant par la fin
...
>>> for item in sorted(container):
# les items sont retournés triés
...
# Somme des valeurs d'un type conteneur
# exemple avec une liste d'entiers:
>>> sum([1,2,3])
6
# Valeur maximum
>>> max([1,2,3])
3
# Valeur minimum
>>> min([1,2,3])
1
# 'all' retourne True si toutes les valeurs du conteneur sont vraies
>>> all(container)
# 'any' retourne True si l'une des valeurs du conteneur est vraie
>>> any(container)
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Compréhensions (ou intensions)
Boucles d'itération plus performantes
Compréhension de liste
liste_resultat = [ expr for item in itérable if cond ]
Compréhension d'ensemble
set_resultat = { expr for item in itérable if cond }
Compréhension de dictionnaire
dict_resultat = { k:v for k,v in itérable if cond }
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Quizz
Comment vérifier qu'un conteneur est vide ?
if len(container) == 0: # 1 point if container: # 5 points :-)
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Quizz
Comment vérifier qu'un élément est dans une liste ?
inside = False # -1 point for v in my_list: inside = v == item if inside: break inside = item in my_list # 5 points :-)
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Quizz
Comment initialiser les valeurs d'un dictionnaire
(cas uniforme) ?
counts = {} # 1 point if item not in counts: counts[item] = 0 counts[item] += 1 from collections import defaultdict counts = defaultdict(int) counts[item] += 1 # 5 points :-)
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice 3
En utilisant des comprehensions:
- Trouver tous les nombres divisibles par 7 entre 1 et 1000
- Trouver tous les nombres de 1 à 1000 qui ont un seul "3" dedans
- Ecrire une fonction count_spaces pour compter les espaces d'une chaîne de caractères
- Renvoyer les consonnes de la phrase "The quick brown fox jumped over the lazy dog"
- Ecrire une fonction list_4_letter_words qui renvoie la liste des mots de 4 lettres d'une phrase donnée
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Solution de l'exercice 3
# nombres divisibles par 7 entre 1 et 1000
print([n for n in range(1,1001) if n%7 == 0])
# les nombres entre 1 et 1000 avec un seul 3 dedans
print([n for n in range(1,1001) if str(n).count('3')==1])
# count_spaces
def count_spaces(sentence):
return sum([1 if x.isspace() else 0 for x in sentence])
assert count_spaces("The quick brown fox jumps on the lazy dog")==8
def count_spaces(sentence):
return sentence.count(" ")
assert count_spaces("The quick brown fox jumps on the lazy dog")==8
# consonnes
consonnes = "".join([c if c not in 'aeiouy' else '' for c in "The quick brown fox jumps on the lazy dog"])
print(consonnes)
# liste des mots de 4 lettres
def list_4_letter_words(sentence):
return list(filter(None, [w if len(w)==4 else None for w in sentence.split(" ")]))
assert list_4_letter_words("The quick brown fox jumps on the lazy dog")==["lazy"]
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice 4
Traduire le R2D2 dans le texte
Récupérer le transcript du message de R2D2 ici
Grouper les 0 et les 1 par 8 pour former des octets, décoder en utilisant la table ASCII, afficher le message
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Solution de l'exercice 4
msg = '01110011001000000110111001101111001000000010000001101001001000000111001101101110001000000110010100100000001000000110100000100000001000000110010100100000011100100010000000100000011100000110110100100000011011110010000001100011'
octets = [msg[i:i+8] for i in range(0, len(msg), 8)]
chars = [chr(int(c, 2)) for c in octets]
removed_spaces = list(filter(None, [c.strip() for c in chars]))
decoded_msg = "".join(reversed(removed_spaces))
print(decoded_msg)
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice 5: Jedis et sabres laser
{'green': 6, 'red': 5, 'blue': 6}
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Solution de l'exercice 5
# avec le module 'collections'
frequencies = collections.Counter(jedi['lightsaber_color'] for jedi in jedis)
# ou bien avec une comprehension de dictionnaire
colors = [jedi['lightsaber_color'] for jedi in jedis]
frequencies = {color: colors.count(color) for color in set(colors)}
print(frequencies)
{'green': 6, 'red': 5, 'blue': 6}
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Paquets et modules
-
Un module est un fichier .py contenant du code Python (définitions, déclarations et expressions exécutables)
- Permet de grouper le code d'un même sous-problème
- Organiser le code facilite le débuggage et le rend plus facile à comprendre
- Un paquet est un ensemble de modules formant une librairie Python
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Anatomie d'un module Python
# -*- coding: utf-8 -*-
import <module1>
from <module2> import <nom>
VARIABLE_GLOBALE = <valeur>
def fonction_quelconque(arg1, arg2, ...):
<code de la fonction>
...
class MaClasse(object):
...
if __name__ == '__main__':
...
< Déclaration de l'encodage du fichier (ISO 10646, compatible ASCII, le plus utilisé)
Optionnel pour utf-8: encodage par défaut
< Importation des dépendances (modules auxiliaires)
< Définition des variables globales
< Définition des fonctions et des classes du module
< Code exécuté uniquement quand l'interpréteur lit le module en tant que script (pas importé depuis un autre module)
mon_module.py
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Définition d'une fonction de multiplication f(x,y)=>x*y, dans un module appelé "test.py"
# -*- coding: utf-8 -*-
def f(x, y):
return x*y
test.py
Utilisation:
(exercices) matias@kashyyyk ~ $ python
Python 3.7.0 (default, Jun 28 2018, 13:15:42)
[GCC 7.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import test
>>> test.f(5,6)
30
(exercices) matias@kashyyyk ~ $ python
Python 3.7.0 (default, Jun 28 2018, 13:15:42)
[GCC 7.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from test import f
>>> f(5,6)
30
>>> f("a", 8)
'aaaaaaaa'
>>>
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Les modules sont des objets comme les autres
- Une fois importé un module Python devient un objet dans le système
- stocké dans sys.modules
- Les objets modules constituent des espaces de noms (namespaces)
- On peut manipuler les propriétés d'un objet module
(exercices) matias@kashyyyk ~ $ python
Python 3.7.0 (default, Jun 28 2018, 13:15:42)
[GCC 7.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import sys #module built-in de Python
>>> import test #notre module de test
>>> print(sys.modules["test"])
<module 'test' from '/tmp/test.py'>
>>> test.toto=42
>>> print(test.toto) # la fonction built-in 'print' affiche un résultat
42
>>> dir(test) # la fonction built-in 'dir' affiche les membres d'un objet
['__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__spec__', 'f', 'toto']
>>>
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Les modules sont des singletons
- une seule instance d'un même module existe dans un programme Python
- elle est partagée entre tous les modules qui l'importent
import test
# 'id' retourne l'adresse d'un objet en mémoire
adresse_memoire_de_test = id(test)
test2.py
import test
# 'id' retourne l'adresse d'un objet en mémoire
adresse_memoire_de_test = id(test)
test3.py
(exercices) matias@kashyyyk ~ $ python
Python 3.7.0 (default, Jun 28 2018, 13:15:42)
[GCC 7.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import test2
>>> import test3
>>> import test
>>> id(test) == test2.adresse_memoire_de_test == test3.adresse_memoire_de_test
True
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Utilisation du module "test" en tant que script Python
# -*- coding: utf-8 -*-
def f(x, y):
return x*y
if __name__ == '__main__':
print(f(5, 6))
test.py
Utilisation:
(exercices) matias@kashyyyk ~ $ python /tmp/test.py
30
exécutable (sous Linux)
< ajout du "shebang"
#!/usr/bin/env python
(exercices) matias@kashyyyk ~ $ chmod +x /tmp/test.py
(exercices) matias@kashyyyk ~ $ /tmp/test.py
30
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Paquet ("package") Python
matias@kashyyyk ~/dev/exemple_paquet $ tree
.
├── test.py
├── bla.py
├── __init__.py
└── toto
├── __init__.py
└── blabla.py
Ensemble de modules dans une arborescence constituant une librairie
< Module membre du paquet
< fichier __init__.py (peut être vide), permet à Python de reconnaître que le répertoire fait partie d'un paquet
sous-répertoire du paquet >
Utilisation:
(exercices) matias@kashyyyk ~/dev/exemple_paquet $ cd ..
(exercices) matias@kashyyyk ~/dev $ python
Python 3.7.0 (default, Jun 28 2018, 13:15:42)
[GCC 7.2.0] :: Anaconda, Inc. on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> from exemple_paquet import test
>>> test.f(5,6)
30
>>>
< Python recherche les paquets dans le répertoire courant et dans ceux définis par la variable d'environnement PYTHONPATH
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice 6a: petit script de multiplication
Ecrire un script "test.py" qui prend un nombre variable de nombres en ligne de commande et qui utilise une fonction "multiply" pour afficher le resultat de la multiplication de ces nombres par eux-memes
python -c "import test; print test.multiply(2,3)"
---> sortie 6.0
python test.py 2 1.5
---> sortie 3.0
python test.py 2 3 4
---> sortie 24
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice 6a: Correction
import sys
def multiply(*n):
res = 1
for x in n:
res *= x
return res
if __name__ == '__main__':
nombres = [float(x) for x in sys.argv[1:]]
print(multiply(*nombres))
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice 6b: le jeu du Pendu
Ecrire un programme de jeu du Pendu, en piochant les mots dans le fichier dictionnaire du système
Proposer à l'utilisateur un mot masqué au hasard, en remplaçant les lettres par "_" et à chaque entrée de caractère vérifier si le caractère figure dans le mot
Si oui : l'afficher
Si non: afficher un élément du pendu, si la potence est complète c'est game over !
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Solution de l'exerice 6: Jeu du Pendu,
lien ici
import random
import os
import sys
import unidecode
HANGMAN = ["""
_______
|/ |
|
|
|
|
|
_|___
""",
"""
_______
|/ |
| (_)
|
|
|
|
_|___
""",
"""
_______
|/ |
| (_)
| \|/
|
|
|
_|___
""",
"""
_______
|/ |
| (_)
| \|/
| |
|
|
_|___
""",
"""
_______
|/ |
| (_)
| \|/
| |
| / L
|
_|___
"""]
def find_word():
word = None
dictionary_file = os.path.join(os.path.dirname(__file__), "french.txt")
with open(dictionary_file, encoding='latin-1') as df:
while True:
i = random.randint(0, 22739)
word = next((line.strip() for j, line in enumerate(df) if i==j))
if word[0].isupper():
df.seek(0)
else:
break
return word
def g_display_hangman():
"""Display hangman"""
for h in HANGMAN:
yield h+'\n'
def g_ask_for_char():
already_tried = []
while True:
input_char = input("Proposer une lettre: ").upper()
if len(input_char) > 1:
continue
if input_char in already_tried:
print(f"Deja essaye: {input_char}")
continue
already_tried.append(input_char)
yield input_char
def display_word(word, found):
print('\n')
print("Mot: {}".format(" ".join([c if found[i] else "_" for i,c in enumerate(word)])))
print('\n')
def start_game(debug):
game_over = False
word = find_word()
assert word is not None
if debug:
print(f'Mot a trouver = {word}')
normalized_word = unidecode.unidecode(word).upper()
found_chars = [False]*len(word)
display_hangman = g_display_hangman()
ask_for_char = g_ask_for_char()
print(next(display_hangman))
while not game_over:
display_word(word, found_chars)
input_char = next(ask_for_char)
if input_char in word.upper():
found_chars = [found_chars[i] or input_char==c for i,c in enumerate(normalized_word)]
if all(found_chars):
break
else:
try:
print(next(display_hangman))
except StopIteration:
game_over = True
if game_over:
print(f"Dommage... Le mot etait: {word}")
else:
print("Super!")
if __name__ == '__main__':
debug = False
if '-d' in sys.argv[1:]:
debug = True
start_game(debug)
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Solution numéro 2 de l'exerice 6: Jeu du Pendu
Pour aller plus loin, avec la librairie graphique Qt
from PyQt5.Qt import Qt, QApplication, QMainWindow, QWidget, QMenuBar, QMenu, QLabel, QVBoxLayout, QHBoxLayout, QMessageBox, QPixmap
import functools
import random
LISTE_MOTS = ["trouver", "ballon", "cyclone", "voiture", "python"]
def generateur_gibet(dessin_pendu):
hangman = [[
"64 47 2 1 ",
" c none",
". c #3D3D3D",
" ",
" ",
" ",
" . . . . . ",
" ......................... ",
" . .. ",
" . .. ",
" .. . ",
" . . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" . ",
" ......................................................... ",
" . . . . . . . . . . . . . . . ",
" ",
" "],
[
"64 47 2 1 ",
" c none",
". c #414141",
" ",
" ",
" ",
" . . . . . ",
" ......................... ",
" . .. ",
" . .. ",
" .. . ",
" . .. ",
" . ....... ",
" . .. . ",
" .. . . . .. ",
" . . .. .. . ",
" . .. . .. ",
" . . .. .. ",
" .. .. . ",
" . .. ... ",
" . .... ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" ......................................................... ",
" . . . . . . . . . . . . . . . ",
" ",
" "],
[
"64 47 2 1 ",
" c none",
". c #414141",
" ",
" ",
" ",
" . . . . . ",
" ......................... ",
" . .. ",
" . .. ",
" .. . ",
" . .. ",
" . ....... ",
" . .. . ",
" .. . . . .. ",
" . . .. .. . ",
" . .. . .. ",
" . . .. .. ",
" .. .. . ",
" . ....... ",
" . ... ",
" . . ",
" . . ",
" . . ",
" .. .. ",
" . . ",
" . . ",
" . . ",
" . . ",
" . . ",
" .. .. ",
" . ",
" . ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" ......................................................... ",
" . . . . . . . . . . . . . . . ",
" ",
" "],
[
"64 47 2 1 ",
" c none",
". c #434343",
" ",
" ",
" ",
" . . . . . ",
" ......................... ",
" . .. ",
" . .. ",
" .. . ",
" . .. ",
" . ....... ",
" . .. . ",
" .. . . .... ",
" . . .. .. . ",
" . .. . . ",
" . . . .. ",
" .. .. . . ",
" . ....... ",
" .. ... ",
" . . ",
" . . . .. ",
" . ........... ",
" .. .. ",
" . . ",
" . . ",
" . . ",
" .. . ",
" . . ",
" . .. ",
" . . ",
" .. ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" ......................................................... ",
" . . . . . . . . . . . . . . . ",
" ",
" "],
[
"64 47 2 1 ",
" c none",
". c #444444",
" ",
" ",
" ",
" . . . . . ",
" ......................... ",
" . .. ",
" . .. ",
" .. . ",
" . .. ",
" . ....... .......... ",
" . .. . ..... ... ",
" .. . . .... . ",
" . . .. .. . . ",
" . .. . . . ",
" . . . .. ",
" .. .. . . ",
" . ....... ",
" . ... ",
" . . ",
" . . . .. . . ",
" .. .................... ",
" . .. ",
" . . ",
" . . ",
" .. . ",
" . . ",
" .. . ",
" . .. ",
" . . ",
" . ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" . ",
" ......................................................... ",
" . . . . . . . . . . . . . . . ",
" ",
" "],
[
"64 47 2 1 ",
" c none",
". c #444444",
" ",
" ",
" ",
" . . . . . ",
" ......................... ",
" . .. ",
" . .. ",
" .. . ",
" . .. ",
" . ....... ",
" . .. . ",
" .. . .. ",
" . . . ",
" . .. .. ",
" . . . .. ",
" .. .. . . ",
" . ....... ",
" .. ... ",
" . . ",
" . . . .. . . ",
" . .................... ",
" .. .. ",
" . . ",
" . . ",
" . . ",
" .. . ",
" . . ",
" . .. ",
" . . ",
" .. ... ",
" . .. .. ",
" . .. . ",
" .. .. .. ",
" . . . ",
" . .. .. ",
" .. .. .. ",
" . .. . ",
" . ",
" . ",
" .. ",
" . ",
" . ",
" ......................................................... ",
" . . . . . . . . . . . . . . . ",
" ",
" "]]
for xpm_data in hangman:
dessin_pendu.setPixmap(QPixmap(xpm_data))
yield
def demarrer_pendu(main_window):
# Zone de jeu en position centrale
zone_jeu = QWidget()
QVBoxLayout(zone_jeu)
zone_jeu.layout().addWidget(QLabel("<center><h1>Mot à trouver:</h1></center>"))
main_window.setCentralWidget(zone_jeu)
hbox = QHBoxLayout(main_window)
dessin_pendu = QLabel(zone_jeu)
dessin_pendu.setScaledContents(True)
dessin_pendu.setFixedWidth(128)
dessin_pendu.setAlignment(Qt.AlignHCenter)
hbox.addWidget(dessin_pendu)
zone_jeu.layout().addLayout(hbox)
# nouveau mot a trouver
mot_a_trouver = random.choice(LISTE_MOTS)
print(mot_a_trouver) #pour le debogage
mot_cherche = ["_"]*len(mot_a_trouver)
label_mot_a_trouver = QLabel()
def affiche_mot_cherche():
label_mot_a_trouver.setText(f"<center><b><h1>{' '.join(mot_cherche)}</h1></b></center>")
zone_jeu.layout().addWidget(label_mot_a_trouver)
def tester(char):
trouve = False
gagne = False
for i, c in enumerate(mot_a_trouver):
if char.lower() == c.lower(): # comparaison en minuscules
mot_cherche[i] = c
trouve = True
gagne = not '_' in mot_cherche
return trouve, gagne
affiche_gibet = generateur_gibet(dessin_pendu)
def gerer_appui_touche(event):
char_code = event.key()
try:
char = chr(char_code)
except ValueError:
pass
else:
trouve, gagne = tester(char)
affiche_mot_cherche()
if not trouve:
try:
next(affiche_gibet)
except StopIteration:
QMessageBox.critical(None, "Dommage", "Perdu... :(")
main_window.keyPressEvent = main_window.saved_keypressevent
zone_jeu.close()
if gagne:
QMessageBox.information(None, "Félicitations!", "C'est gagné")
main_window.keyPressEvent = main_window.saved_keypressevent
zone_jeu.close()
main_window.saved_keypressevent = main_window.keyPressEvent #sauver la fonction
main_window.keyPressEvent = gerer_appui_touche #remplacer la fonction par la notre
affiche_mot_cherche()
if __name__ == '__main__':
# Creation de l'application
app = QApplication([])
# Fenetre principale
main_window = QMainWindow()
main_window.setMinimumSize(500,500)
main_window.setWindowTitle("Jeu du Pendu")
# Barre de menu
menu = QMenuBar()
main_window.setMenuBar(menu)
# Menu
menu_partie = QMenu("Partie")
menu_partie.addSeparator()
menu.addMenu(menu_partie)
action_demarrer = menu_partie.addAction("Démarrer")
action_demarrer.triggered.connect(functools.partial(demarrer_pendu, main_window))
action_quitter = menu_partie.addAction("Quitter")
action_quitter.triggered.connect(main_window.close)
# Afficher la fenetre et entrer dans la boucle de Qt
main_window.show()
app.exec_()
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Exercice 6c:
Décodage basique des informations d'un fichier PNG
Lire la page wikipedia concernant le format PNG, et écrire le programme prenant un fichier en ligne de commande, et affichant le maximum d'informations provenant du fichier
Aide: le module 'struct' permet de décoder des données binaires
2. Installation
3. Premiers pas
Introduction
1. Présentation du langage
Solution de l'exercice 6c
import sys
import struct
import zlib
COLOR_MODES = { 3: "indexed colors",
2: "truecolor",
6: "truecolor with alpha",
0: "greyscale",
4: "greyscale with alpha" }
COMPRESSION_METHOD = { 0: "deflate" }
def check_signature(f):
signature = b"\x89\x50\x4e\x47\x0d\x0a\x1a\x0a"
assert signature == f.read(len(signature))
def read_chunk(f):
chunk_length = struct.unpack(">i", f.read(4))[0]
chunk_type = struct.unpack(">4s", f.read(4))[0]
chunk_data = f.read(chunk_length)
chunk_crc = f.read(4)
return chunk_type, chunk_data
def read_png(filename):
with open(filename, "rb") as f:
check_signature(f)
chunk_type, chunk_data = read_chunk(f)
assert chunk_type == b"IHDR"
width, height, depth, color_mode, compression_method, filtering_method, _ = struct.unpack(">iiccccc", chunk_data)
depth = ord(depth)
color_mode = ord(color_mode)
compression_method = ord(compression_method)
filtering_method = ord(filtering_method)
assert filtering_method == 0
print(f"PNG image, {width}x{height}, {depth} bits per channel, color mode: {COLOR_MODES[color_mode]}, compression: {COMPRESSION_METHOD[compression_method]}")
raw_data = b""
while True:
chunk_type, chunk_data = read_chunk(f)
if chunk_type == b"IEND":
break
elif chunk_type == b"IDAT":
raw_data += chunk_data
raw_data = zlib.decompress(raw_data)
# each line of the image in data is in the form: <filter> r g b a
assert len(raw_data)==width*height*4+height
if __name__ == '__main__':
read_png(sys.argv[1])
Charmer le Python
Charmer le Python
Générateurs et Coroutines
Gestion de Contexte
Décorateurs
Multiprocessing
4
Fonctionalités avancées
6
POO en Python
Le paradigme objet
Classes, méthodes et objets
Encapsulation
Héritage
Composition
Evaluation des connaissances
5
Charmer le Python
4. Fonctionalités avancées
Générateurs
5. Evaluation
6. POO en Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Générateurs
Un générateur est une fonction qui se comporte comme un itérateur
Rappel: itérateur = qui renvoie des valeurs dans une boucle for, exemple: list, string, dict, etc.
Charmer le Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Le mot-clef "yield"
yield a la même fonctionnalité que return, sauf que l'exécution de la fonction ne termine pas: on peut la rappeler pour continuer après yield
L'utilisation du mot-clef yield transforme une fonction en générateur
def f(n):
i = 0
while i<n:
yield i
i += 1
>>> g=f(5)
>>> g
<generator object f at 0x7fe8fe259ee8>
>>> next(g)
0
>>> next(g)
1
>>> next(g)
2
>>> next(g)
3
>>> next(g)
4
>>> next(g)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
< i est retourné quand le générateur est exécuté; l'exécution suivante reprendra juste après
< appeler f() renvoie un objet "generator"
< la fonction next() déroule le générateur
< StopIteration est levée quand la fonction est terminée
# exemple avec plusieurs yield
def f():
yield "Début"
for i in range(3):
yield i
yield "Fin"
>>> list(f())
['Début', 0, 1, 2, 'Fin']
Charmer le Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Generator Expression
Cousin de la compréhension de liste, dont l'implémentation utilise un générateur
(expression for i in s if condition)
Syntaxe générale
Traduction avec une boucle "for"
for i in s: if condition: yield expression
Charmer le Python
Coroutine
Le générateur produit des données ; la coroutine peut aussi consommer des données
def creer_fontaine(contenu):
while True:
x = yield contenu
if x:
contenu = x
>>> f = creer_fontaine("soda")
>>> next(f)
soda
>>> next(f)
soda
>>> f.send("lait")
lait
>>> next(f)
lait
< .send() permet d'envoyer une valeur: le yield en attente retourne la valeur envoyée, et next() est rappelé automatiquement
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Utilisation des générateurs et des coroutines
Lazy Evaluation,
c'est-à-dire évaluation à la dernière minute, pour ne pas devoir préparer toutes les valeurs à l'avance
Processing Pipelines
Machines d'Etats
Lien vers l'article
Lien vers l'article
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Gestion de Contexte
Le mot-clef with permet de créer un contexte d'exécution
= un raccourci pour try...finally, plus lisible dans le code, réutilisable, et en un seul bloc
# ouvrir un fichier, le lire, et être
# sûr de le fermer même si une exception survient
try:
f = open("/tmp/bla")
...
finally:
f.close()
# meme chose avec with
with open("/tmp/bla") as f:
...
NB: la fonction doit implémenter le protocole de gestion de contexte... Toutes les fonctions ne gèrent pas les contextes
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Comment écrire un context manager sous forme de fonction
from contextlib import contextmanager
@contextmanager
def ma_fonction():
# tout le code avant yield est exécuté
# à l'entrée du contexte (au moment du 'with')
...
yield X # la valeur X est récupérable avec 'as'
...
# tout le code après yield est exécuté à la
# sortie du contexte
< Utilisation du module contextlib de la librairie standard
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exercice 7
Ecrire un context manager qui permet de mesurer le temps (en millisecondes) pris par un bloc de code
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Solution de l'exercice 7
from contextlib import contextmanager
import time
@contextmanager
def timeit():
t0 = time.time()
yield
elapsed_time = 1000*(time.time()-t0)
print("Execution took {} ms".format(elapsed_time))
with timeit():
print("Je dors...")
time.sleep(1)
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
@décorateurs
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Fonction qui permet d'étendre les fonctionalités d'une autre fonction sans la modifier
Qu'est-ce qu'un décorateur ?
Mathématiquement, décorer une fonction correspond à l'opération de composition 'rond' (notée o), telle que pour 2 fonctions f et g:
f o g(x) = f(g(x))
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Ecriture d'un décorateur
# écriture de f o g(x) en Python,
# tel que f o g(x) = f[g(x)]
# 1. fonction décorateur
def f(fonction_à_décorer):
def fonction_composée(x):
nom_fonction_décorée = fonction_à_décorer.__name__
print(f"Bienvenue dans la fonction composée 'f o {nom_fonction_décorée}'")
print(f"Je renvoie le carré du résultat de {nom_fonction_décorée}")
res = fonction_à_décorer(x)
print(f"La fonction {nom_fonction_décorée} a renvoyé {res}")
print("Je renvoie ce résultat au carré")
return res**2
return fonction_composée
# 2. définition
>>> @f
... def g(x):
... return 2*x
>>>
# 3. Execution
>>> g(3)
Bienvenue dans la fonction composée 'f o g'
Je renvoie le carré du résultat de g
La fonction g a renvoyé 6
Je renvoie ce résultat au carré
36
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exemple d'utilisation: réessayer d'appeler automatiquement une fonction qui produit une exception
def retry_on_exception_decorator(n):
def decorator(func):
def wrapped_func(*args, **kwargs):
i = n
last_exception = None
while i > 0:
try:
ret = func(*args, **kwargs)
except Exception as e:
last_exception = e
i -= 1
else:
return ret
raise last_exception
return wrapped_func
return decorator
retry = retry_on_exception_decorator(3)
< Closure (fermeture): fonction accompagnée de son environnement lexical (ici, la variable 'n')
>
on ne peut pas modifier les variables d'une closure donc on la réassigne à "i"
import urllib.request
@retry
def get_url(url):
with urllib.request.urlopen(url) as r:
if r.getcode() != 200:
raise RuntimeError(f"Failed to retrieve data from {url}")
return r.read()
get_url("http://www.google.fr")
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Memoization: LRU (Last Recent Used) cache
Une fonction dotée de "mémoization" conserve les résultats de ses appels successifs, pour retourner immédiatement un résultat si elle est appelée avec les mêmes arguments
from functools import lru_cache
@lru_cache
def do_heavy_job(*args, **kwargs):
... some heavy calculation here ...
return result
>>> do_heavy_job(1,2)
... compute ...
result
>>> do_heavy_job(1,2)
result
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exercice 8: écriture d'un décorateur "check_type" pour vérification du type des arguments d'une fonction
@check_type(str, city=(str,None))
def greeting(name, city=None):
print(f"Hello, {name}{' from '+city if city else ''} !")
>>> greeting("Alex", "Voiron")
Hello, Alex from Voiron !
>>> greeting("Juan")
Hello, Juan !
>>> greeting("Albert", city=42)
TypeError: Arg. 42 has an invalid type, expected: <class 'str'>
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Solution de l'exercice 8
def check_type(*args, **kwargs):
def check(x, types):
try:
types = tuple(types)
except TypeError:
if type(x)!=types:
raise TypeError(f"Arg. {x} has an invalid type, expected: {str(type)}")
else:
if not any(type(x)==t for t in types):
raise TypeError(f"Arg. {x} has an invalid type, expected one of: {','.join([str(t) for t in types])}")
def decorator(func):
def wrapped_func(*func_args, **func_kwargs):
for arg, arg_types in zip(func_args, args):
check(arg, arg_types)
for arg_name, arg in func_kwargs.items():
arg_types = kwargs[arg_name]
check(arg, arg_types)
return func(*func_args, **func_kwargs)
return wrapped_func
return decorator
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
6. Projets Python
Multiprocessing
Lire l'excellente présentation de David Beazley sur le sujet ici
(dont sont tirés les schémas de cette partie du cours)
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Notion de concurrence
Programmation concurrente: écriture de programmes pouvant exécuter plusieurs choses à la fois
La concurrence implique le multi-tâche
S'il n'y a qu'un seul CPU, la seule manière d'être multi-tâche est de passer (très) rapidement d'une tâche à une autre
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Parallélisme
Le "vrai" parallélisme intervient quand plusieurs CPU peuvent exécuter des tâches en même temps
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exécution des tâches d'un CPU
Les tâches font:
- soit des calculs, des opérations sur les variables, du traitement
- soit des entrées/sorties
< Opération bloquante au niveau du système
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
2 types de programmes
"CPU bound"
"I/O bound" (le plus courant)
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
La concurrence en Python: Threads
Fil d'exécution indépendant
GIL (Global Interpreter Lock)
Mémoire et ressources partagées
Synchronisation,
"race conditions"
Exécution préemptive
opération non-atomiques
"ok" (en faisant bien attention...) pour les tâches "I/O bound"
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
La concurrence en Python: multiprocessing
pas de mémoire partagée
communication via messages (Inter-Process Communication)
pas de limitation du GIL entre les tâches
très utile pour les tâches "CPU bound"
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Utilisation du module multiprocessing
import multiprocessing
import time
def countdown(count):
while count > 0:
print("Counting down", count)
count -= 1
time.sleep(3)
if __name__ == '__main__':
p1 = multiprocessing.Process(target=countdown,
args=(10,))
p1.start()
p1.join() # attendre la fin du process
Quizz: est-ce que le code présenté dans cet exemple est I/O bound ou CPU bound ?
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Communication entre les process
Un moyen simple et efficace de communiquer entre les process démarrés par multiprocessing est d'utiliser un objet Queue
In [1]: from multiprocessing import Process, Queue
...:
...: def multiplier(factor, queue):
...: n = queue.get()
...: queue.put(n*factor)
...:
In [2]: q = Queue()
In [3]: p1 = Process(target=multiplier, args=(2, q, ))
In [4]: p1.start()
In [5]: q.put(6)
In [6]: q.get()
Out[6]: 12
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Synchronisation
L'objet multiprocessing.Event est adapté pour permettre de synchroniser les process
from multiprocessing import Process, Queue, Event
started_event = Event()
queue = Queue()
def multiplier(factor, queue, started_event):
started_event.set()
n = queue.get()
queue.put(factor * n)
p1 = Process(target=multiplier, args=(2, queue, started_event))
p1.start()
started_event.wait()
queue.put(6)
print(queue.get()) # affiche 12
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Sérialisation de la communication
Les données qui s'échangent entre les process doivent être sérialisées
C'est-à-dire encodées pour pouvoir être transférées
L'objet Queue de multiprocessing le gère de façon transparente à l'aide du module pickle
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
multiprocessing.Pool
L'objet Pool de multiprocessing offre une méthode pratique pour paralléliser l'éxécution de code
Pool.map s'utilise de la même manière que la fonction "map" built-in
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
6. Projets Python
Exercice 9: convertir une image en niveaux de gris
Utiliser le module multiprocessing pour convertir une image couleur de Lena en niveaux de gris
Decouper l'image en parties et faire la moyenne des valeurs R,G,B de chaque pixel dans des process Python differents (utilisation de multiprocessing.Pool)
Ecrire la nouvelle image en niveaux de gris dans le fichier choisi par l'utilisateur au format .png
Utiliser le package pillow (PIL), bien penser à itertools, functools, collections qui peuvent être utiles
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
6. Projets Python
Comparer le temps d'exécution avec un seul thread (= sans multiprocessing)
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
6. Projets Python
Recommencer avec une image beaucoup plus grande
(liens ici)
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
from PIL import Image
import requests
import io
import multiprocessing
import itertools
import more_itertools
import contextlib
import time
@contextlib.contextmanager
def timeit():
t0 = time.perf_counter()
yield
print(f"Function took {1000*(time.perf_counter()-t0)} ms.")
imgdata = requests.get("https://i.stack.imgur.com/3T6Gc.jpg").content
imgdata_as_a_file = io.BytesIO(imgdata)
im = Image.open(imgdata_as_a_file)
def convert_to_greyscale(data):
return [sum(rgb)//3 for rgb in data]
with timeit():
pixels_greyscale = convert_to_greyscale(im.getdata())
#im_greyscale = Image.new("L", im.size)
#im_greyscale.putdata(pixels_greyscale)
pixels = im.width * im.height
ncpus = multiprocessing.cpu_count()
chunk_size = pixels//ncpus
with timeit():
with multiprocessing.Pool(ncpus) as pool:
sub_data = pool.map(convert_to_greyscale, more_itertools.chunked(im.getdata(), chunk_size))
pixels_greyscale = itertools.chain(*sub_data)
im_greyscale = Image.new("L", im.size)
im_greyscale.putdata(list(pixels_greyscale))
im_greyscale.show()
6. Projets Python
Suite de l'exercice 9
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
A la suite de la conversion en niveaux de gris, calculer l'histogramme de l'image
(c'est-à-dire: compter combien il y a de pixels de chaque niveau de gris)
Sauvegarder l'histogramme à l'aide du package matplotlib, sous forme de fichier .png
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Corrigé du test ici
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Programmation Orientée Object en Python
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Le paradigme objet
Modéliser les données et les opérations sur les données d'un problème avec des représentants abstraits (des objets dans du code)
Les objets sont issus de classes
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Qu'est-ce qu'une classe ?
classe
= le "patron" (au sens manufacturier) des objets
objet
= instance de la classe
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
4 concepts clefs
Abstraction
Eliminer le superflu, amplifier l'essentiel
Cacher ce qui n'est pas nécessaire de connaître
Modélisation de la similarité
Même fonction, différents comportements
Héritage
Polymorphisme
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Représentation schématique d'une classe
MachineACafé |
---|
propriétés + finesse_mouture + temperature |
méthodes privées - _chauffer_eau() - _moudre_le_grain(quantité) - _faire_couler(quantité_eau) |
méthodes publiques + faire_café(quantité_café, quantité_eau) |
< utilisées en interne, non disponibles pour l'utilisateur de l'objet final (en théorie)
< API utilisateur
< équivalent de "getter" et "setter" en Java ; peuvent être publiques ou privées, selon les mêmes conventions que les méthodes
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Enough talk, show me the code !
class MachineACafé:
def __init__(self):
self._temperature = 50
self._finesse_mouture = "moyen"
def _chauffer_eau(self):
pass
def _moudre_grains(self, quantité):
pass
def _faire_couler(self, quantité_eau):
pass
def _signaler_café_prêt(self):
print("Veuillez prendre votre café.")
def faire_café(self, quantité_café, quantité_eau):
self._chauffer_eau()
self._moudre_grains(quantité_café)
self._faire_couler(quantité_eau)
self._signaler_café_prêt()
< méthode spéciale : __init__ est le "constructeur" de la classe
< toutes les méthodes reçoivent un premier argument spécial: l'instance de l'objet sur lequel la méthode est appelé (traditionnellement appelé "self" -ou "this" en Javascript)
>>> delonghi_pro = MachineACafé()
>>> type(delonghi_pro)
<class '__main__.MachineACafé'>
>>> dir(delonghi_pro)
['__class__', '__delattr__', '__dict__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__',
'__le__', '__lt__', '__module__', '__ne__', '__new__', '__reduce__',
'__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__',
'__subclasshook__', '__weakref__',
'_chauffer_eau', '_faire_couler', '_finesse_mouture', '_moudre_grains',
'_signaler_café_prêt', '_temperature', 'faire_café']
>>> delonghi_pro.faire_café(10,80)
Veuillez prendre votre café.
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exercice 10
- écrire une classe pour représenter une porte (méthodes ouvrir(), fermer(), propriété état -ouvert ou fermé- etc.)
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Encapsulation:
Le décorateur @property
Similaire au principe du "getter/setter" populaire en Java, mais à la sauce Python
Permet d'emballer (encapsuler) des détails d'implémentation dans une API plus simple
Les propriétés peuvent être en lecture seule (read-only) ou en lecture/écriture
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exemple de @property
class Animal:
def __init__(self, type, couleur):
self._type = type
self._couleur = couleur
@property
def type(self):
return self._type
@property
def couleur(self):
return self._couleur
>>> titi=Animal("oiseau", "jaune")
>>> titi.type
'oiseau'
>>> titi.type="chat"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: can't set attribute
>>>
< par défaut une property est read-only
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exemple de @property (2)
class Animal:
def __init__(self, type, couleur):
self._type = type
self._couleur = couleur
self._état = None
@property
def état(self):
if not self._état:
return "inconnu"
else:
return self._état
@état.setter
def état(self, nouvel_état):
états_autorisés = ("endormi", "éveillé", "agressif", "en rut")
if not nouvel_état in états_autorisés:
raise ValueError(f"Etat invalide, choisir parmi: {', '.join(états_autorisés)}")
self._état = nouvel_état
>>> a=Animal("oiseau", "jaune")
>>> a.état
'inconnu'
>>> a.état="joyeux"
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/tmp/bla.py", line 18, in état
raise ValueError(f"Etat invalide, choisir parmi: {', '.join(états_autorisés)}")
ValueError: Etat invalide, choisir parmi: endormi, éveillé, agressif, en rut
>>> a.état="en rut"
>>>
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exercice 11
Ecrire une classe pour représenter un cercle avec des propriétés rayon, diamètre, et des méthodes aire(), périmètre()
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Solution de l'exercice 11
import math
class Cercle:
def __init__(self, rayon):
self._rayon = rayon
@property
def rayon(self):
return self._rayon
@rayon.setter
def rayon(self, r):
self._rayon = r
@property
def diametre(self):
return 2*self.rayon
@diametre.setter
def diametre(self, d):
self.rayon = d/2.
def calculer_aire(self):
return math.pi*self.rayon**2
def calculer_perimetre(self):
return 2*math.pi*self.rayon
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exercice 11b: compte bancaire
- Créer une classe Python nommée CompteBancaire qui représente un compte bancaire, ayant pour propriétés : numeroCompte, nom (nom du propriétaire du compte du type chaine), solde.
- Créer un constructeur ayant comme paramètres : numeroCompte, nom, solde.
- Créer une méthode Versement() qui gère les versements.
- Créer une méthode Retrait() qui gère les retraits
- Empêcher d'être à découvert
- Utiliser __repr__ pour faire un affichage des informations du compte
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Solution de l'exercice 11b
class CompteBancaire:
def __init__(self, numeroCompte, nom, solde):
self.__numeroCompte = numeroCompte
self.__nom = nom
self.__solde = solde
@property
def numeroCompte(self):
return self.__numeroCompte
@property
def nom(self):
return self.__nom
@property
def solde(self):
return self.__solde
def versement(self, somme):
self.__solde += somme
def retrait(self, somme):
if self.__solde < somme:
raise ValueError("Désolé la banque ne fait pas crédit")
self.__solde -= somme
def __repr__(self):
print(f"Compte numero {self.numeroCompte}")
print(f"Client: {self.nom}")
print(f"Solde: {self.solde} euros")
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exercice 11c: compte bancaire II
6. Créer une méthode "ajouterTitulaire" pour créer un compte joint (2 personnes, ou plus)
- penser à modifier l'affichage
7. créer une propriété découvertAutorisé qui donne le droit d'être à découvert, jusqu'à un montant maximal
8. ajouter une méthode pour appliquer des frais lors d'un retrait en cas de découvert (5% du montant total du découvert)
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Solution exercice 11c
import random
class CompteBancaire:
def __init__(self, nom, solde):
self.__numeroCompte = 100000+random.randint(0,100000)
self.__nom = nom
self.__solde = solde
self.__cotitulaires = []
self.__decouvertAutorise = 0
@property
def numeroCompte(self):
return self.__numeroCompte
@property
def nom(self):
return self.__nom
@property
def solde(self):
return self.__solde
@property
def titulaires(self):
return [self.nom] + self.__cotitulaires
@property
def decouvertAutorise(self):
return self.__decouvertAutorise
@decouvertAutorise.setter
def decouvertAutorise(self, somme):
self.__decouvertAutorise = somme
def versement(self, somme):
self.__solde += somme
def retrait(self, somme):
if self.__solde < somme:
if abs(self.__solde - somme) > self.decouvertAutorise:
raise ValueError("Désolé la banque ne fait pas crédit")
self.__solde -= somme
self.appliquerFrais()
def appliquerFrais(self):
if self.__solde < 0:
self.__solde -= 0.05*abs(self.__solde)
def __repr__(self):
s = f"Compte numero {self.numeroCompte}\n"
s += f"{'Titulaire' if not self.__cotitulaires else 'Titulaires'}: {', '.join(self.titulaires)}\n"
s += f"Solde: {self.solde} euros\n"
return s
def ajouterTitulaire(self, nom):
self.__cotitulaires.append(nom)
if __name__ == "__main__":
cpte = CompteBancaire("Martin", 5000)
assert cpte.numeroCompte
assert cpte.solde == 5000
assert cpte.nom == "Martin"
cpte.ajouterTitulaire("Olivia")
assert cpte.titulaires == ["Martin", "Olivia"]
cpte.versement(3000)
assert cpte.solde == 8000
cpte.retrait(4000)
assert cpte.solde == 4000
assert cpte.decouvertAutorise == 0
try:
cpte.retrait(5000)
except ValueError:
assert True
else:
assert False
cpte.decouvertAutorise = 1000
assert cpte.decouvertAutorise == 1000
cpte.retrait(4500)
assert cpte.solde == -500-(0.05*500)
cpte.retrait(300)
assert cpte.solde == -825-(0.05*825)
cpte.versement(3000)
assert cpte.solde == 2133.75
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Méthodes spéciales
Il existe de nombreuses méthodes spéciales (cf. la doc Python...)
__init__() est la plus connue : constructeur de la classe
__str__() est bien utile aussi
class Animal:
...
def __str__(self):
return f"Je suis un {self.type} {self.état}."
>>> gros_minet=Animal("chat", "noir")
>>> gros_minet.état="agressif"
>>> print(gros_minet)
'Je suis un chat agressif.'
>>>
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Héritage
Permettre de créer une nouvelle classe en réutilisant une classe existante
Uniquement valable lorsqu'il y a une relation "EST UN" ("IS A") entre 2 objets
La nouvelle classe dispose de toutes les propriétés et des méthodes de la classe de base, et peut les modifier ou les étendre
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Héritage (2)
Ne pas comprendre la relation "IS A" au sens le plus strict... C'est vrai dans 80% des cas seulement
Par exemple: le cas du rectangle et du carré
Un carré est un rectangle MAIS les comportements des deux objets sont trop différents, comme avec la largeur et la longueur. Voir le LSP (lien ici)
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exemple d'Héritage
class AnimalDomestique(Animal):
def __init__(self, nom, type, couleur):
super().__init__(type, couleur)
self._nom = nom
@property
def nom(self):
return self._nom
def __str__(self):
base_str = super().__str__()
return base_str+f" Je m'appelle {self.nom}."
< super() permet d'appeler la classe de base (ici, le constructeur d'Animal)
>>> coco=AnimalDomestique("Coco", "oiseau", "vert")
>>> coco.état="endormi"
>>> print(coco)
"Je suis un oiseau endormi. Je m'appelle Coco."
>>>
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exercice 12: écrire la classe Chien et la classe Chat
Le chien EST UN animal domestique
Le chat aussi
Ajouter une méthode "aboyer" au chien
Ajouter une méthode "miauler" au chat
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Composition
La composition consiste à ajouter des méthodes ou des propriétés à une classe en déléguant à d'autres objets
class PuceElectronique:
def __init__(self, id):
self._id = id
self._nom_proprio = None
self._adresse_proprio = None
@property
def id(self):
return self._id
@property
def nom_proprio(self):
return self._nom_proprio
@property
def adresse_proprio(self):
return self._adresse_proprio
def définir_propriétaire(self, nom, adresse):
self._nom = nom
self._adresse = adresse
class AnimalDomestique:
def __init__(...):
self._puce = None
def mettre_puce(self, puce):
self._puce = puce
@property
def propriétaire(self):
if not self._puce:
return ""
return self._puce.nom_proprio
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Composition vs Héritage
Dans la programmation de tous les jours, la composition est beaucoup plus utile que l'héritage
Soyez prudent avec l'héritage, en tant que développeur débutant
(pareil que les threads !)
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Exercice 13: porte avec serrure
Réutiliser la classe Porte de l'exercice précédent, pour créer une classe PorteAvecSerrure
Les serrures peuvent être de 2 types:
- à clef
- à digicode
Utiliser la composition
6. Projets Python
5. Evaluation
6. POO en Python
4. Fonctionalités avancées
Charmer le Python
Pour des explications peu conventionnelles et un peu datées mais néanmoins très utiles c'est par ici
Pour aller plus loin...
Python en Prod
Python en Prod
6
Projets Python
Debugging
Ecriture de tests
Fichier setup.py
Débuter en Python
By Matias Guijarro
Débuter en Python
- 2,100