II. Initiation à Python▲
II-A. Introduction▲
II-A-1. Installation▲
Cette introduction repose essentiellement sur les outils suivants :
- Python 2.7 (inclus l'interpréteur de base et la bibliothèque standard) ;
- les bibliothèques scientifiques Numpy et Scipy ;
- la bibliothèque graphique Matplotlib ;
- un interpréteur évolué, p.ex. ipython ;
- un éditeur de texte évolué, p.ex. emacs, vi, gedit ou Atom.
Ces logiciels peuvent être installés indépendamment, de préférence sous Linux (p.ex. Ubuntu ou votre distribution préférée), ou sous Windows ou MacOS. Il existe également des distributions « clés en main » :
- Anaconda (multiplateforme) ;
- Python(x,y) (Windows) ;
- Enthought Canopy (Windows, MacOS, Linux, gratuite pour les étudiants du supérieur).
II-A-2. Notions d'Unix▲
Les concepts suivants sont supposés connus :
- ligne de commande : exécutables et options ;
- arborescence : chemin relatif (./]...) et absolu (/...), navigation (cd) ;
- gestion des fichiers (ls, rm, mv) et répertoires (mkdir) ;
- gestion des exécutables : $PATH, chmod +x ;
- gestion des processus : &, Control-c, Control-z + bg ;
- variables d'environnement : export, .bashrc .
Liens :
II-A-3. L'invite de commande▲
Il existe principalement deux interpréteurs intéractifs de commandes Python :
- Python : interpréteur de base :
2.
3.
4.
5.
$ python
Python 2.7.6
(
default, Mar 22
2014
, 22
:59
:56
)
[GCC 4.8.2
] on linux2
Type "help"
, "copyright"
, "credits"
or
"license"
for
more information.
>>>
- Control-d pour sortir ;
- help(commande) pour obtenir l'aide d'une commande ;
- A priori, pas d'historique des commandes ni de complétion automatique.
L'interpréteur de base permet également d'interpréter un « script », c.-à-d. un ensemble de commandes regroupées dans un fichier texte (généralement avec une extension .py) : python mon_script.py.
- ipython : interpréteur évolué (avec historique et complétion automatique des commandes) :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
$
ipython
Python 2
.7
.12
(
default, Nov 19
2016
, 06
:48
:10
)
Type "copyright"
, "credits"
or "license"
for
more information.
IPython 5
.3
.0
-- An enhanced Interactive Python.
? ->
Introduction and overview of IPython's features.
%quickref -> Quick reference.
help -> Python'
s own help system.
object? ->
Details about 'object'
, use 'object??'
for
extra details.
In
[1
]:
- Control-d pour sortir ;
- Tab pour la complétion automatique ;
- Haut et Bas pour le rappel des commandes ;
- Aide ipython : object? pour une aide sur un objet, object?? pour une aide plus complète (au niveau source) ;
-
Commandes magic (voir %magic) :
- %run mon_script.py pour exécuter un script dans l'interpréteur,
- %debug pour lancer le mode débogage interactif postmortem,
- %cpaste pour coller et exécuter un code préformaté.
Liens :
II-B. Types de base▲
- None (rien)
-
Chaînes de caractères : str
- Entre (simples ou triples) apostrophes ' ou guillemets " :
'Calvin'
,"Calvin'n'Hobbes"
,'''Deux
\n
lignes'''
,"""'Pourquoi?' demanda-t-il."""
- Conversion : str
(
3.2
)
- Entre (simples ou triples) apostrophes ' ou guillemets " :
-
Types numériques :
2.
3.
4.
5.
6.
7.
8.
9.
10.
>>>
5
/
2
# !!! Division euclidienne par défaut dans Python 2.x !!!
2
>>>
float(
5
)/
2
# ou ajouter 'from __future__ import division' en début de script
2.5
>>>
6
//
2.5
# Division euclidienne explicite
2.0
>>>
6
%
2.5
# Reste de la division euclidienne
1.0
>>>
(
1
+
2
j)**-
0.5
# Puissance entière, réelle ou complexe
(
0.5688644810057831
-
0.3515775842541429
j)
-
Objets itérables :
- Listes list : [
'a'
,3
, [1
,2
],'a'
] - Listes immuables tuple :
(
2
,3.1
, [1
+
0
j],'a'
) (selon les conditions d'utilisation, les parenthèses ne sont pas toujours nécessaires) - Listes à clés dict : {
'a'
:1
,'b'
:[1
,2
],3
:'c'
} -
Ensembles non ordonnés d'éléments uniques set : {
1
,2
,3
,2
}Sélectionnez1.
2.
3.
4.
5.
6.
7.
8.>>>
l=
['a'
,True
]# Définition d'une liste
>>>
x, y=
1
,2.5
# Affectations multiples via tuples (les parenthèses ne sont pas nécessaires)
>>>
range(
5
)# Liste de 5 entiers commençant par 0
[0
,1
,2
,3
,4
]>>>
l+
[x, y]# Concaténation de listes
['a'
,True
,1
,2.5
]>>>
{2
,1
,3
}|
{1
,2
,'a'
}# Union d'ensembles
{'a'
,1
,2
,3
}
- Listes list : [
- type
(
obj) retourne le type de l'objet, isinstance(
obj, type) teste le type de l'objet.
2.
3.
4.
>>>
type(
l)
<
type 'list'
>
>>>
isinstance(
l, tuple)
False
Liens :
II-C. Structures de programmation▲
-
Les blocs sont définis par l'indentation (en général par pas de quatre espaces)(1).
Évitez autant que possible les caractères de tabulation, source de confusion. Configurez votre éditeur de texte pour qu'il n'utilise que des espaces.
-
Une instruction par ligne en général (ou instructions séparées par ;).
-
Les commentaires commencent par #, et s'étendent jusqu'à la fin de la ligne.
-
Expression booléenne : une condition est une expression s'évaluant à
True
ouFalse
:False
: test logique faux (p.ex.3
==
4
), valeur nulle, chaîne vide (''
), liste vide ([]), etc.True
: test logique vrai (p.ex.2
+
2
==
4
), toute valeur ou objet non nul (et donc s'évaluant par défaut àTrue
sauf exception)-
Tests logiques :
==
,!=
,>
,>=
, etc.Ne pas confondre «
=
» (affectation d'une variable) et «==
» (test logique d'égalité).
-
Opérateurs logiques :
and
,or
,not
Sélectionnez>>>
(
5
>=
6
)or
(
not
3
>
4
)True
- Opérateur ternaire (PEP 308) : value
if
conditionelse
altvalue, p.ex.
>>>
y =
x**
0.5
if
(
x >
0
) else
0
# Retourne sqrt(max(x, 0))
- Expression conditionnelle :
if
condition: ... [elif
condition2: ...] [else
: ...], p.ex. :
2.
3.
4.
5.
6.
if
(
i >
0
): # Condition principale
print
"positif"
elif
(
i <
0
): # Condition secondaire (si nécessaire)
print
"négatif"
else
: # Cas final (si nécessaire)
print
"nul"
- Boucle for :
for
elementin
iterable , s'exécute sur chacun des éléments d'un objet itérable :
2.
3.
4.
5.
>>>
for
val in
['un'
, (
2
, 3
), 4
]: # Itération sur une liste de 3 éléments
... print
val
un
(
2
, 3
)
4
continue
: interrompt l'itération courante, et reprend la boucle à l'itération suivante,break
: interrompt complètement la boucle.
la logique des boucles Python est assez différente des langages C[++]/fortran, pour lesquels l'itération porte sur les indices plutôt que sur les éléments eux-mêmes.
- Boucle while :
while
condition : se répète tant que la condition est vraie, ou jusqu'à une sortie explicite avecbreak
.
Attention aux boucles infinies, dont la condition d'exécution reste invariablement vraie (typiquement un critère de convergence qui n'est jamais atteint). On peut toujours s'en protéger en testant en outre sur un nombre maximal (raisonnable) d'itérations :
2.
3.
4.
niter =
0
while
(
error >
1e-6
) and
(
niter <
100
):
error =
... # A priori, error va décroître, et la boucle s'interrompre
niter +=
1
# Mais on n'est jamais assez prudent !
Exercices :
II-D. Les chaînes de caractères▲
II-D-1. Indexation▲
Les chaînes de caractères sont des objets itérables - c.-à-d. constitués d'éléments (ici les caractères) sur lesquels il est possible de « boucler » (p.ex. avec for
) - et immuables - c.-à-d. dont les éléments individuels ne peuvent pas être modifiés intrinsèquement.
Comme en C[++], l'indexation en Python commence à 0 : le 1er élément d'une liste est l'élément n° 0, le 2e est le n° 1, etc. Les n éléments d'une liste sont donc indexés de 0 à n-1.
2.
3.
4.
5.
6.
7.
>>>
alpha =
'abcdefghijklmnopqrstuvwxyz'
>>>
len(
alpha)
26
>>>
alpha[0
] # 1er élément (l'indexation commence à 0)
'a'
>>>
alpha[-
1
] # = alpha[26-1=25], dernier élément (-2: avant-dernier, etc.)
'z'
II-D-2. Sous-liste (slice)▲
Des portions d'une chaîne peuvent être extraites en utilisant des slice (« tranches »), de notation générique [start=
0
]:[stop=
len][:step=
1
]. P.ex.
2.
3.
4.
5.
6.
7.
8.
9.
10.
>>>
alpha[3
:7
] # De l'élément n°3 (inclus) au n°7 (exclu), soit 7-3=4 éléments
'defg'
>>>
alpha[:3
] # Du n°0 (défaut) au n°3 (exclu), soit 3 éléments
'abc'
>>>
alpha[-
3
:] # Du n°26-3=23 (inclus) au dernier inclus (défaut)
'xyz'
>>>
alpha[8
:23
:3
] # Du n°8 (inclus) au n°23 (exclu), tous les 3 éléments
'iloru'
>>>
alpha[::5
] # Du 1er au dernier élément (défauts), tous les 5 éléments
'afkpuz'
II-D-3. Méthodes▲
Les chaînes de caractères disposent de nombreuses fonctionnalités - appelées « méthodes » en POOProgrammation Orientée Objet - facilitant leur manipulation :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
>>>
enfant, peluche =
"Calvin"
, 'Hobbes'
# Affectations mutiples
>>>
titre =
enfant +
' et '
+
peluche; titre # +: Concaténation de chaînes
'Calvin et Hobbes'
>>>
titre.replace
(
'et'
, '&'
) # Remplacement de sous-chaînes (→ nouvelle chaîne)
'Calvin & Hobbes'
>>>
titre # titre est immuable et reste inchangé
'Calvin et Hobbes'
>>>
' & '
.join
(
titre.split
(
' et '
)) # Découpage (split) et jonction (join)
'Calvin & Hobbes'
>>>
'Hobbes'
in
titre # in: Test d'inclusion
True
>>>
titre.find
(
"Hobbes"
) # str.find: Recherche de sous-chaîne
10
>>>
titre.center
(
30
, '-'
)
'-------Calvin et Hobbes-------'
>>>
dir(
str) # Liste toutes les méthodes des chaînes
II-D-4. Formatage▲
Le système de formatage permet un contrôle précis de la conversion de variables en chaînes de caractères. Il s'appuie essentiellement sur la méthode str.format
(
) :
2.
3.
4.
5.
6.
7.
8.
9.
>>>
"{0} a {1} ans"
.format
(
'Calvin'
, 6
) # args
'Calvin a 6 ans'
>>>
"{} a {} ans"
.format
(
'Calvin'
, 6
) # Raccourci
'Calvin a 6 ans'
>>>
"{nom} a {age} ans"
.format
(
nom=
'Calvin'
, age=
6
) # kwargs
'Calvin a 6 ans'
>>>
pi =
3.1415926535897931
>>>
"{x:f} {x:.2f} {y:f} {y:g}"
.format
(
x=
pi, y=
pi*
1e9
) # Options de formatage
'3.141593 3.14 3141592653.589793 3.14159e+09'
print() affiche à l'écran (plus spécifiquement la sortie standard) la conversion d'une variable en chaîne de caractères :
2.
3.
4.
5.
>>>
print
"Calvin and Hobbes
\n
Scientific progress goes 'boink'"
Calvin and
Hobbes
Scientific progress goes 'boink'
>>>
print
"{0:2d} fois {1:2d} font {2}"
.format
(
3
, 4
, 3
*
4
) # Formatage et affichage
3
fois 4
font 12
Exercice :
II-E. Objets itérables▲
Les chaînes de caractères, listes, tuples et dictionnaires sont les objets itérables de base en Python. Les listes et dictionnaires sont modifiables (« mutables ») - leurs éléments constitutifs peuvent être changés à la volée - tandis que chaînes de caractères et les tuples sont immuables.
-
Accès indexé : conforme à celui des chaînes de caractères
Sélectionnez1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.>>>
l=
range(
1
,10
,2
); l# De 1 (inclus) à 10 (exclu) par pas de 2
[1
,3
,5
,7
,9
]>>>
len(
l)# Nb d'éléments dans la liste (i varie de 0 à 4)
5
>>>
l[0
], l[-
2
]# 1er et avant-dernier élément (l'indexation commence à 0)
(
1
,7
)>>>
l[5
]# Erreur: indice hors-bornes
IndexError
: list index out of range>>>
d=
dict(
a=
1
, b=
2
)# Création du dictionnaire {'a':1, 'b':2}
>>>
d['a'
]# Accès à une entrée via sa clé
1
>>>
d['c'
]# Erreur: clé inexistante !
KeyError
:'c'
>>>
d['c'
]=
3
; d# Ajout d'une clé et sa valeur
{'a'
:1
,'c'
:3
,'b'
:2
}>>>
# Noter qu'un dictionnaire N'est PAS ordonné !
-
Sous-listes (slices) :
Sélectionnez1.
2.
3.
4.
5.
6.>>>
l[1
:-
1
]# Du 2e ('1') *inclus* au dernier ('-1') *exclu*
[3
,5
,7
]>>>
l[1
:-
1
:2
]# Idem, tous les 2 éléments
[3
,7
]>>>
l[::2
]# Tous les 2 éléments (*start=0* et *stop=len* par défaut)
[1
,5
,9
] -
Modification d'éléments d'une liste (chaînes et tuples sont immuables) :
Sélectionnez1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.>>>
l[0
]=
'a'
; l# Remplacement du 1er élément
['a'
,3
,5
,7
,9
]>>>
l[1
::2
]=
['x'
,'y'
]; l# Remplacement d'éléments par *slices*
['a'
,'x'
,5
,'y'
,9
]>>>
l+
[1
,2
]; l# Concaténation (l reste inchangé)
['a'
,'x'
,5
,'y'
,9
,1
,2
] ['a'
,'x'
,5
,'y'
,9
]>>>
l+=
[1
,2
]; l# Concaténation sur place (l est modifié)
['a'
,'x'
,5
,'y'
,9
,1
,2
]>>>
l.append
(
'z'
); l# Ajout d'un élément en fin de liste
['a'
,'x'
,5
,'y'
,9
,1
,2
,'z'
]>>>
l.extend
(
[-
1
,-
2
]); l# Extension par une liste
['a'
,'x'
,5
,'y'
,9
,1
,2
,'z'
,-
1
,-
2
]>>>
del
l[-
6
:]; l# Efface les 6 derniers éléments de la liste
['a'
,'x'
,5
,'y'
]Attention à la modification des objets mutables :
Sélectionnez1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.>>>
l=
range(
3
)# l pointe vers la liste [0, 1, 2]
>>>
m=
l; m# m est un *alias* de la liste l: c'est le même objet
[0
,1
,2
]>>>
id(
l); id(
m); mis
l171573452
# id({obj}) retourne le n° d'identification en mémoire
171573452
# m et l ont le même id:
True
# ils correspondent donc bien au même objet en mémoire
>>>
l[0
]=
'a'
; m# puisque l a été modifiée, il en est de même de m
['a'
,1
,2
]>>>
m=
l[:]# copie de tous les éléments de l dans une *nouvelle* liste m (clonage)
>>>
id(
l); id(
m); mis
l171573452
171161228
# m a un id différent de l: il s'agit de 2 objets distincts
False
# (contenant éventuellement la même chose !)
>>>
del
l[-
1
]; m# les éléments de m n'ont pas été modifiés
['a'
,1
,2
] - Liste en compréhension : elle permet la construction d'une liste à la volée
2.
3.
4.
5.
6.
7.
8.
9.
10.
>>>
[ i**
2
for
i in
range(
5
) ] # Carré de tous les éléments de [0, ..., 4]
[0
, 1
, 4
, 9
, 16
]
>>>
[ 2
*
i for
i in
range(
10
) if
(
i%
3
!=
0
) ] # Compréhension conditionnelle
[2
, 4
, 8
, 10
, 14
, 16
]
>>>
[ 10
*
i+
j for
i in
range(
3
) for
j in
range(
4
) ] # Double compréhension
[0
, 1
, 2
, 3
, 10
, 11
, 12
, 13
, 20
, 21
, 22
, 23
]
>>>
[ [ 10
*
i+
j for
i in
range(
3
) ] for
j in
range(
4
) ] # Compréhensions imbriquées
[[0
, 10
, 20
], [1
, 11
, 21
], [2
, 12
, 22
], [3
, 13
, 23
]]
>>>
{ i: i**
2
for
i in
range(
1
, 5
) } # Dictionnaire en compréhension
{1
: 1
, 2
: 4
, 3
: 9
, 4
: 16
}
- Utilitaires sur les itérables :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
>>>
humans =
['Calvin'
, 'Wallace'
, 'Boule'
]
>>>
for
i in
range(
len(
humans)): # Boucle sur les indices de humans
... print
i, humans[i] # Accès explicite, pas pythonique :-(
0
Calvin
1
Wallace
2
Boule
>>>
for
i, name in
enumerate(
humans): # Boucle sur (indice, valeur) de humans
... print
i, name # Pythonique :-D
0
Calvin
1
Wallace
2
Boule
>>>
animals =
['Hobbes'
, 'Gromit'
, 'Bill'
]
>>>
for
boy, dog in
zip(
humans, animals): # Boucle simultanée sur 2 listes (ou +)
... print
boy, 'et'
, dog
Calvin et Hobbes
Wallace et Gromit
Boule et Bill
>>>
sorted
(
zip(
humans, animals)) # Tri, ici sur le 1er élément de chaque tuple de la liste
[(
'Boule'
, 'Bill'
), (
'Calvin'
, 'Hobbes'
), (
'Wallace'
, 'Gromit'
)]
Exercices :
II-F. Fonctions▲
Une fonction est un regroupement d'instructions impératives - assignations, branchements, boucles, etc. - s'appliquant sur des arguments d'entrée. C'est le concept central de la programmation impérative.
def
permet de définir une fonction :
def
fonction
(
arg1, arg2, ..., option1=
valeur1, option2=
valeur2, ...):
Les « args » sont des arguments nécessaires (c.-à-d. obligatoires), tandis que les « kwargs » - arguments de type option=
valeur - sont optionnels, puisqu'ils possèdent une valeur par défaut. Si la fonction doit retourner une valeur, celle-ci est spécifiée par le mot-clé return
.
Exemples :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
def
temp_f2c
(
tf):
"""
Convertit une température en d° Fahrenheit `tf` en d° Celsius.
Exemple:
>>>
temp_f2c
(
104
)
40.0
"""
tc =
(
tf -
32.
)/
1.8
# Fahrenheit ? Celsius
return
tc
Dans la définition d'une fonction, la première chaîne de caractères (appelé docstring) servira de documentation pour la fonction, accessible de l'interpréteur via p.ex. help
(
temp_f2c), ou temp_f2c? sous ipython. Elle se doit d'être tout à la fois pertinente, concise et complète. Elle peut également inclure des exemples d'utilisation (doctests, voir Développement piloté par les testsDéveloppement piloté par les tests).
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
def
mean_power
(
alist, power=
1
):
"""
Retourne la racine `power` de la moyenne des éléments de `alist` à
la puissance `power`:
.. math:: \mu = (
\f
ra
c{1}
{N}\sum_{i=0}^{N-1} x_i^p)^{1/p}
`power=1` correspond à la moyenne arithmétique, `power=2` au *Root
Mean Squared*, etc.
Exemples:
>>>
mean_power
(
[1
, 2
, 3
])
2.0
>>>
mean_power
(
[1
, 2
, 3
], power=
2
)
2.160246899469287
"""
s =
0.
# Initialisation de la variable *s* comme *float*
for
val in
alist: # Boucle sur les éléments de *alist*
s +=
val **
power # *s* est augmenté de *val* puissance *power*
# *mean* = (somme valeurs / nb valeurs)**(1/power)
mean =
(
s /
len(
alist)) **
(
1
/
power) # ATTENTION aux divisions euclidiennes !
return
mean
Il faut noter plusieurs choses importantes :
- Python est un langage à typage dynamique, p.ex., le type des arguments d'une fonction n'est pas fixé a priori. Dans l'exemple précédent, alist peut être une list, un tuple ou tout autre itérable contenant des éléments pour lesquels les opérations effectuées - somme, exponentiation, division par un entier - ont été préalablement définies (p.ex. des entiers, des complexes, des matrices, etc.) ;
- le typage est fort, c.-à-d. que le type d'une variable ne peut pas changer à la volée. Ainsi,
"abra"
+
"cadabra"
a un sens (concaténation de chaînes), mais pas3
+
"cochons"
(entier + chaîne) ; - la définition d'une fonction se fait dans un « espace parallèle » où les variables ont une portée (scope) locale(2). Ainsi, la variable s définie dans la fonction mean_power n'interfère pas avec le « monde extérieur » ; inversement, la définition de mean_power ne connaît a priori rien d'autre que les variables explicitement définies dans la liste des arguments ou localement.
Exercice :
II-G. Bibliothèques et scripts▲
II-G-1. Bibliothèques externes▲
Une bibliothèque (ou module) est un code fournissant des fonctionnalités supplémentaires - p.ex. des fonctions prédéfinies - à Python. Ainsi, le module math définit les fonctions et constantes mathématiques usuelles (sqrt
(
), pi, etc.).
Une bibliothèque est « importée » avec la commande import
module. Les fonctionnalités supplémentaires sont alors accessibles dans l'espace de noms module via module.fonction :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
>>>
sqrt
(
2
) # sqrt n'est pas une fonction standard de python
NameError
: name 'sqrt'
is
not
defined
>>>
import
math # Importe tout le module 'math'
>>>
dir(
math) # Liste les fonctionnalités de 'math'
['__doc__'
, '__name__'
, '__package__'
, 'acos'
, 'acosh'
, 'asin'
,
'asinh'
, 'atan'
, 'atan2'
, 'atanh'
, 'ceil'
, 'copysign'
, 'cos'
, 'cosh'
,
'degrees'
, 'e'
, 'exp'
, 'fabs'
, 'factorial'
, 'floor'
, 'fmod'
, 'frexp'
,
'fsum'
, 'hypot'
, 'isinf'
, 'isnan'
, 'ldexp'
, 'log'
, 'log10'
, 'log1p'
,
'modf'
, 'pi'
, 'pow'
, 'radians'
, 'sin'
, 'sinh'
, 'sqrt'
, 'tan'
, 'tanh'
,
'trunc'
]
>>>
math.sqrt
(
math.pi) # Les fonctionnalités sont disponibles sous 'math'
1.7724538509055159
>>>
import
math as
M # Importe 'math' dans l'espace 'M'
>>>
M.sqrt
(
M.pi)
1.7724538509055159
>>>
from
math import
sqrt, pi # Importe uniquement 'sqrt' et 'pi' dans l'espace courant
>>>
sqrt
(
pi)
1.7724538509055159
Il est possible d'importer toutes les fonctionnalités d'une bibliothèque dans l'espace de noms courant :
2.
3.
>>>
from
math import
*
# Argh ! Pas pythonique :-(
>>>
sqrt
(
pi)
1.7724538509055159
Cette pratique est cependant fortement déconseillée du fait des confusions dans les espaces de noms qu'elle peut entraîner :
>>>
from
cmath import
*
>>>
sqrt
(-
1
) # Quel sqrt: le réel ou le complexe ?
Nous verrons par la suite quelques exemples de modules de la Bibliothèque standardBibliothèque standard, ainsi que des Bibliothèques numériques de baseBibliothèques numériques de base orientées analyse numérique.
Exercice :
Flocon de Koch (programmation récursive) ★★★Flocon de Koch (programmation récursive) ★★★
II-G-2. Bibliothèques personnelles et scripts▲
Vous pouvez définir vos propres bibliothèques en regroupant les fonctionnalités au sein d'un même fichier monfichier.py.
- Si ce fichier est importé (p.ex.
import
monfichier), il agira comme une bibliothèque. - Si ce fichier est exécuté - p.ex. python ./monfichier.py - il agira comme un script.
Toutes les instructions d'un module qui ne sont pas encapsulées dans le __main__ (voir plus bas) sont interprétées et exécutées lors de l'import
du module. Elles doivent donc en général se limiter à la définition de variables, de fonctions et de classes (en particulier, éviter les affichages ou les calculs longs).
Un code Python peut donc être :
- un module - s'il n'inclut que des définitions mais pas d'instruction exécutable en dehors d'un éventuel __main__ ;
- un exécutable - s'il inclut un __main__ ou des instructions exécutables ;
- ou les deux à la fois.
Exemple
Le code mean_power.pyMean power (fonction, argparse) peut être importé comme une bibliothèque (p.ex. import
mean_power) dans un autre code Python, ou bien être exécuté depuis la ligne de commande (p.ex. python mean_power.py), auquel cas la partie __main__ sera exécutée.
-
#!
(Hash-bang) : la première ligne d'un script défini l'interpréteur à utiliser(3) :Sélectionnez#!/usr/bin/env python
-
Un fichier incluant des caractères non ASCII (p.ex. caractères accentués, ou symboles UTF tels que ±) doit définir le système d'encodage, généralement utf-8 :
Sélectionnez# -*- coding: utf-8 -*-
Notez que les noms de variables, fonctions, etc. doivent être purement ASCII (a-zA-Z0-9_). De manière générale, favorisez la langue anglaise (variables, commentaires, affichages).
-
"""doc"""
: la chaîne de documentation de la bibliothèque (docstring, PEP 257), qui sera utilisée comme aide en ligne du module (help
(
mean_power)), doit être la 1re instruction du script. -
from
__future__
import
division : permet de ne pas considérer les divisions entre entiers comme euclidiennes par défaut. if
__name__
==
'__main__'
: permet de séparer le __main__ (c.-à-d. le corps du programme, à exécuter lors d'une utilisation en script) des définitions de fonctions et classes, permettant une utilisation en module.
II-H. Exceptions▲
Lorsqu'il rencontre une erreur dans l'exécution d'une instruction, l'interpréteur Python génère (raise
) une erreur (Exception
), de nature différente selon la nature de l'erreur : KeyError
, ValueError
, AttributeError
, NameError
, TypeError
, IOError
, NotImplementedError
, etc. La levée d'une erreur n'est cependant pas nécessairement fatale, puisque Python dispose d'un mécanisme de gestion des erreurs.
Il est d'usage en Python d'utiliser la philosophie EAFPEasier to Ask for Forgiveness than Permission[4] : plutôt que de tester explicitement toutes les conditions de validité d'une instruction, on « tente sa chance » d'abord, quitte à gérer les erreurs a posteriori. Cette gestion des Exception
se fait par la construction try
... except
.
2.
3.
4.
5.
6.
7.
>>>
lireEntier
(
)
Entrez un entier: toto
'toto'
n'est pas un entier
Entrez un entier: 3,4
'
3
,4
' n'
est pas un entier
Entrez un entier: 4
4
Dans l'élaboration d'un programme, gérez explicitement les erreurs que vous auriez pu tester a priori et pour lesquels il existe une solution de repli, et laissez passer les autres (ce qui provoquera éventuellement l'interruption du programme).
Évitez à tout prix les except
nus, c.-à-d. ne spécifiant pas la ou les exceptions à gérer, car ils intercepteraient alors toutes les exceptions, y compris celles que vous n'aviez pas prévues ! Trouvez l'erreur dans le code suivant :
2.
3.
4.
5.
6.
y =
2
try
:
x =
z # Copie y dans x
print
"Tout va bien"
except
:
print
"Rien ne va plus"
Vos procédures doivent également générer des exceptions (documentées) - avec l'instruction raise
Exception
- si elles ne peuvent conclure leur action, à charge pour la procédure appelante de les gérer si besoin :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
def
diff_sqr
(
x, y):
"""
Return x**2 - y**2 for x >= y, raise ValueError otherwise.
Exemples:
>>>
diff_sqr
(
5
, 3
)
16
>>>
diff_sqr
(
3
, 5
)
Traceback (most recent call last):
...
ValueError: x=3 < y=5
"""
if
x <
y:
raise
ValueError
(
"x={} < y={}"
.format
(
x, y))
return
x**
2
-
y**
2
Avant de se lancer dans un calcul long et complexe, on peut vouloir tester la validité de certaines hypothèses fondamentales, soit par une structure if
... raise
, ou plus facilement à l'aide d'assert
(qui, si l'hypothèse n'est pas vérifiée, génère une AssertionError
) :
2.
3.
4.
5.
6.
7.
def
diff_sqr
(
x, y):
"""
Returns x**2 - y**2 for x >= y, AssertionError otherwise.
"""
assert
x >=
y, "x={} < y={}"
.format
(
x, y) # Test et msg d'erreur
return
x**
2
-
y**
2
La règle générale à retenir concernant la gestion des erreurs :
Fail early, fail often, fail better !
Exercice :
Jeu du plus ou moins (exceptions) ★Jeu du plus ou moins (exceptions) ★
II-I. Classes▲
Un objet est une entité de programmation, disposant de ses propres états et fonctionnalités. C'est le concept central de la Programmation Orientée Objet.
Au concept d'objet sont liées les notions de :
- Classe : il s'agit d'un modèle d'objet, dans lequel sont définis ses propriétés usuelles. P.ex. la classe Forme peut représenter une forme plane caractérisée par sa couleur, et disposant de fonctionnalités propres, p.ex.
change_couleur
(
) ; - Instanciation : c'est le fait générer un objet concret (une instance) à partir d'un modèle (une classe). P.ex. rosie
=
Forme
(
'rose'
) crée une instance rosie à partir de la classe Forme et d'une couleur (chaîne de caractères'rose'
) ; - Attributs : variables internes décrivant l'état de l'objet. P.ex., rosie.couleur donne la couleur de la Forme rosie ;
-
Méthodes : fonctions internes, s'appliquant en premier lieu sur l'objet lui-même (self), décrivant les capacités de l'objet. P.ex. rosie.
change_couleur
(
'bleu'
) change la couleur de la Forme rosie.Toutes les méthodes d'une classe doivent au moins prendre self - représentant l'objet lui-même - comme premier argument.
-
Surcharge d'opérateurs : cela permet de redéfinir les opérateurs et fonctions usuels (
+
, abs(
), str(
), etc.), pour simplifier l'écriture d'opérations sur les objets. Ainsi, on peut redéfinir les opérateurs de comparaison (<
,>=
, etc.) dans la classe Forme pour que les opérations du genre forme1<
forme2 aient un sens (p.ex. en comparant les aires).
Liste des méthodes standard et des surcharges d'opérateur ; - Héritage de classe : il s'agit de définir une classe à partir d'une (ou plusieurs) classe(s) parente(s). La nouvelle classe hérite des attributs et méthodes de sa (ses) parente(s), que l'on peut alors modifier ou compléter. P.ex. la classe Rectangle hérite de la classe Forme (elle partage la notion de couleur et d'aire), et lui ajoute des méthodes propres à la notion de rectangle (p.ex. formule explicite de l'aire, étirement).
Toutes les classes doivent au moins hériter de la classe principale object.
Exemple de définition de classe
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
class
Forme
(
object): # *object* est la classe dont dérivent toutes les autres
"""Une forme plane, avec éventuellement une couleur."""
def
__init__
(
self, couleur=
None
):
"""Initialisation d'une Forme, sans couleur par défaut."""
if
couleur is
None
:
self.couleur =
'indéfinie'
else
:
self.couleur =
couleur
def
__str__
(
self):
"""
Surcharge de la fonction `str()`: l'affichage *informel* de
l'objet dans l'interpréteur, p.ex. `print a` sera résolu comme
`a.__str__()`
Retourne une chaîne de caractères.
"""
return
"Forme encore indéfinie de couleur {}"
.format
(
self.couleur)
def
change_couleur
(
self, newcolor):
"""Change la couleur de la Forme."""
self.couleur =
newcolor
def
aire
(
self):
"""
Renvoi l'aire de la Forme.
L'aire ne peut pas être calculée dans le cas où la forme n'est
pas encore spécifiée: c'est ce que l'on appelle une méthode
'abstraite', qui pourra être précisée dans les classes filles.
"""
raise
NotImplementedError
(
"Impossible de calculer l'aire d'une forme indéfinie."
)
def
__cmp__
(
self, other):
"""
Comparaison de deux Formes sur la base de leur aire.
Surcharge des opérateurs de comparaison de type `{self} <
{other}`: la comparaison sera résolue comme
`self.__cmp__(other)` et le résultat sera correctement
interprété.
.. WARNING:: cette construction n'est plus supportée en Python3.
"""
return
cmp(
self.aire
(
), other.aire
(
)) # Opérateur de comparaison
Exemple d'héritage de classe
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
class
Rectangle
(
Forme):
"""
Un Rectangle est une Forme particulière.
La classe fille hérite des attributs et méthodes de la
classe mère, mais peut les surcharger (i.e. en changer la
définition), ou en ajouter de nouveaux :
- les méthodes `Rectangle.change_couleur()` et
`Rectangle.__cmp__()` dérivent directement de
`Forme.change_couleur()` et `Forme.__cmp__()`;
- `Rectangle.__str__()` surcharge `Forme.__str__()`;
- `Rectangle.aire()` définit la méthode jusqu'alors abstraite
`Forme.aire()`;
- `Rectangle.allonger()` est une nouvelle méthode propre à
`Rectangle`.
"""
def
__init__
(
self, longueur, largeur, couleur=
None
):
"""
Initialisation d'un Rectangle longueur × largeur, sans couleur par
défaut.
"""
# Initialisation de la classe parente (nécessaire pour assurer
# l'héritage)
Forme.__init__
(
self, couleur)
# Attributs propres à la classe Rectangle
self.longueur =
longueur
self.largeur =
largeur
def
__str__
(
self):
"""Surcharge de `Forme.__str__()`."""
return
"Rectangle {}x{}, de couleur {}"
.format
(
self.longueur, self.largeur, self.couleur)
def
aire
(
self):
"""
Renvoie l'aire du Rectangle.
Cette méthode définit la méthode abstraite `Forme.area()`,
pour les Rectangles uniquement.
"""
return
self.longueur *
self.largeur
def
allonger
(
self, facteur):
"""Multiplie la *longueur* du Rectangle par un facteur"""
self.longueur *=
facteur
Il est traditionnel de commencer les noms de classes avec une majuscule (Forme), et les noms d'instances de classes (les variables) avec une minuscule (rosie).
Exemples
Études de cas
Exercices :
II-J. Entrées-sorties▲
II-J-1. Intéractif▲
Comme nous avons pu le voir précédemment, l'affichage à l'écran se fait par print, la lecture du clavier par raw_input.
II-J-2. Fichiers▲
La gestion des fichiers (lecture et écriture) se fait à partir de la fonction open() retournant un objet de type file :
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
# ========== ÉCRITURE ==========
outfile =
open(
"carres.dat"
, 'w'
) # Ouverture du fichier "carres.dat" en écriture
for
i in
range(
1
, 10
):
outfile.write
(
"{} {}
\n
"
.format
(
i, i**
2
)) # Noter la présence du '\n' (non automatique)
outfile.close
(
) # Fermeture du fichier (nécessaire)
# ========== LECTURE ==========
infile =
open(
"carres.dat"
) # Ouverture du fichier "carres.dat" en lecture
for
line in
infile: # Boucle sur les lignes du fichier
if
line.strip
(
).startswith
(
'#'
): # Ne pas considérer les lignes "commentées"
continue
try
: # Essayons de lire 2 entiers sur cette ligne
x, x2 =
[ int(
tok) for
tok in
line.split
(
) ]
except
ValueError
: # Gestion des erreurs
print
"Cannot decipher line '{}'"
.format
(
line)
continue
print
"{}**3 = {}"
.format
(
x, x**
3
)
II-K. Éléments passés sous silence▲
Cette (brève) introduction à Python se limite à des fonctionnalités relativement simples du langage. De nombreuses fonctionnalités du langage n'ont pas été abordées :
- v ;
- arguments anonymes :
*
args et**
kwargs ; - fonction anonyme :
lambda
x, y: x+
y ; - itérateurs et générateurs :
yield
; - gestion de contexte :
with
...as
(PEP 243) ; - décorateurs : fonction sur une fonction ou une classe (
@staticmethod
, etc.) ; - héritages multiples et méthodes de résolution ;
- etc.
Ces fonctionnalités peuvent évidemment être très utiles, mais ne sont généralement pas strictement indispensables pour une première utilisation de Python dans un contexte scientifique.
II-K-1. Python 3.x▲
Pour des raisons historiques autant que pratiques(4), ce cours présente le langage Python dans sa version 2.x. Pourtant, le développement actuel de Python se fait uniquement sur la branche 3.x, qui constitue une remise à plat non rétrocompatible du langage, et la branche 2.x ne sera a priori plus supporté au-delà de 2020 (PEP 466). Il est donc préférable, si vous vous lancez dans un développement substantiel, de passer aussi rapidement que possible à Python 3 (voir Python 2 vs. python 3Python 2 vs. Python 3).
Python 3 apporte quelques changements fondamentaux, notamment :
print
n'est plus un mot-clé mais une fonction :print
(
...) ;- l'opérateur
/
ne réalise plus la division euclidienne entre les entiers, mais toujours la division réelle ; - un support complet (mais encore complexe) des chaînes Unicode ;
- un nouveau système de formatage des chaînes de caractères (f
-
string du PEP 498 à partir de Python 3.6).