I. Premiers pas▲
Démarrez le shell IPython (un shell Python avancé) :
- soit en tapant ipython depuis un terminal Linux/Mac, ou depuis cmd sous Windows ;
- soit en démarrant le programme depuis un menu, par exemple Python(x,y) ou EPD si vous avez installé une de ces suites Python pour scientifiques.
Si vous n'avez pas IPython d'installé sur votre ordinateur, sachez que d'autres shell Python sont disponibles, comme le shell Python de base que vous pouvez lancer en tapant python dans un terminal, ou encore l'interpréteur IDLE. Cependant, nous vous recommandons d'utiliser le shell IPython en raison de ses fonctionnalités avancées, spécialement en ce qui concerne le calcul scientifique interactif.
Une fois que vous avez lancé l'interpréteur, veuillez saisir :
>>>
print
"Hello, world!"
Hello, world!
Le message Hello, world ! est alors affiché à l'écran. Vous venez juste d'exécuter votre première instruction Python, toutes nos félicitations !
Pour continuer sur votre lancée, veuillez saisir l'ensemble des instructions suivantes :
>>>
a =
3
>>>
b =
2
*
a
>>>
type(
b)
<
type 'int'
>
>>>
print
b
6
>>>
a*
b
18
>>>
b =
'hello'
>>>
type(
b)
<
type 'str'
>
>>>
b +
b
'hellohello'
>>>
2
*
b
'hellohello'
Deux variables a et b sont définies ci-dessus. Veuillez noter qu'on ne déclare pas le type d'une variable avant de lui assigner une valeur. En C, nous aurions dû écrire :
int
a =
3
;
De plus, le type d'une variable peut changer, comprenez que dans un premier temps, la variable peut être d'un type donné, puis que dans un second temps, la variable sera d'un type différent. Ainsi, b fut d'abord un entier, puis devint une chaîne de caractères (string), quand on lui assigna la valeur " hello ". Les opérations sur les entiers (exemple : b = 2*a) sont codées de manière naturelle en Python, de même que les opérations sur les chaînes de caractères. Ainsi l'utilisation des additions et des multiplications sur une chaîne de caractères correspondront respectivement à une concaténation et à une répétition.
II. Les types de base▲
II-A. Types numériques▲
Python supporte les types numériques et scalaires suivants :
Entiers : |
|
Flottants : |
|
Complexes : |
|
Booléens : |
Un shell Python peut parfaitement remplacer votre calculatrice de poche, avec les opérateurs arithmétiques de base +, -, *, /, % (modulo), implémentés nativement.
>>>
7
*
3.
21.0
>>>
2
**
10
1024
>>>
8
%
3
2
Transtypage :
>>>
float(
1
)
1.0
Division entière :
>>>
3
/
2
1
Utilisation des flottants
>>>
3
/
2.
1.5
>>>
a =
3
>>>
b =
2
>>>
a /
b
1
>>>
a /
float(
b)
1.5
Si vous désirez une division avec un résultat entier, utilisez // :
>>>
3.0
//
2
1.0
Le fonctionnement de la division a été modifié dans Python 3. Veuillez vous reporter à http://python3porting.com/preparing.html#use-instead-of-when-dividing-integers pour plus d'informations.
II-B. Les conteneurs▲
Python fournit différents types de conteneurs puissants, dans lesquels nous pouvons stocker des listes ou des objets.
II-B-1. Listes▲
Une liste est un jeu de données et/ou d'objets qui peuvent être de différents types. Par exemple :
Indexation : accès distinct à chaque objet contenu dans la liste :
>>>
L[2
]
'green'
Partir de la fin avec des indices négatifs :
>>>
L[-
1
]
'white'
>>>
L[-
2
]
'black'
Les indices commencent à 0 (comme en C), pas à 1 (comme en Fortran ou Matlab) !
Découpage : obtenir un fragment de la liste :
>>>
L
['red'
, 'blue'
, 'green'
, 'black'
, 'white'
]
>>>
L[2
:4
]
['green'
, 'black'
]
Veuillez noter que L[start:stop] contient les éléments pour lesquels start <= i < stop (i va alors de start à stop-1). Autrement dit, L[start:stop] extrait (stop-start) éléments de la liste.
Syntaxe du slicing : L[start:stop:intervalle]
Tous les paramètres de l'échantillonnage sont optionnels :
>>>
L
['red'
, 'blue'
, 'green'
, 'black'
, 'white'
]
>>>
L[3
:]
['black'
, 'white'
]
>>>
L[:3
]
['red'
, 'blue'
, 'green'
]
>>>
L[::2
]
['red'
, 'green'
, 'white'
]
Les listes sont des objets mutables et peuvent par conséquent être modifiées :
>>>
L[0
] =
'yellow'
>>>
L
['yellow'
, 'blue'
, 'green'
, 'black'
, 'white'
]
>>>
L[2
:4
] =
['gray'
, 'purple'
]
>>>
L
['yellow'
, 'blue'
, 'gray'
, 'purple'
, 'white'
]
Les éléments d'une liste peuvent être de différents types :
>>>
L =
[3
, -
200
, 'hello'
]
>>>
L
[3
, -
200
, 'hello'
]
>>>
L[1
], L[2
]
(-
200
, 'hello'
)
Pour un jeu de données numériques qui sont toutes du même type, il est souvent plus efficace d'utiliser un Array, un tableau, issu du module NumPy. Un tableau NumPy est un bloc mémoire contenant des éléments identiques. Avec les tableaux NumPy, les opérations peuvent être plus rapides car la disposition des éléments en mémoire est régulière et permet l'utilisation de routines en C à la place de boucles Python.
Python offre un large panel de fonctions pour modifier des listes, ou les interroger. Voici quelques exemples ; pour plus d'informations, veuillez consulter http://docs.python.org/tutorial/datastructures.html#more-on-lists.
Ajouter et supprimer des éléments :
>>>
L =
['red'
, 'blue'
, 'green'
, 'black'
, 'white'
]
>>>
L.append
(
'pink'
)
>>>
L
['red'
, 'blue'
, 'green'
, 'black'
, 'white'
, 'pink'
]
>>>
L.pop
(
) # removes and returns the last item
'pink'
>>>
L
['red'
, 'blue'
, 'green'
, 'black'
, 'white'
]
>>>
L.extend
(
['pink'
, 'purple'
]) # extend L, in-place
>>>
L
['red'
, 'blue'
, 'green'
, 'black'
, 'white'
, 'pink'
, 'purple'
]
>>>
L =
L[:-
2
]
>>>
L
['red'
, 'blue'
, 'green'
, 'black'
, 'white'
]
Inverser une liste :
>>>
r =
L[::-
1
]
>>>
r
['white'
, 'black'
, 'green'
, 'blue'
, 'red'
]
>>>
r2 =
list(
L)
>>>
r2
['red'
, 'blue'
, 'green'
, 'black'
, 'white'
]
>>>
r2.reverse
(
) # in-place
>>>
r2
['white'
, 'black'
, 'green'
, 'blue'
, 'red'
]
Concaténer et répéter une liste :
>>>
r +
L
['white'
, 'black'
, 'green'
, 'blue'
, 'red'
, 'red'
, 'blue'
, 'green'
, 'black'
, 'white'
]
>>>
r *
2
['white'
, 'black'
, 'green'
, 'blue'
, 'red'
, 'white'
, 'black'
, 'green'
, 'blue'
, 'red'
]
Trier une liste :
>>>
sorted
(
r) # new object
['black'
, 'blue'
, 'green'
, 'red'
, 'white'
]
>>>
r
['white'
, 'black'
, 'green'
, 'blue'
, 'red'
]
>>>
r.sort
(
) # in-place
>>>
r
['black'
, 'blue'
, 'green'
, 'red'
, 'white'
]
M éthodes et POO
La notation r.method() (par exemple r.append(3) et L.pop()) constitue notre premier exemple de POO. Étant une liste, l'objet r possède la fonction method qui est appelée en utilisant la notation ".". Il n'y a aucun autre principe de la POO plus important que de comprendre la notation "." pour continuer ce tutoriel.
Méthodes de découvertes
Rappelez-vous : dans IPython, la complétion s'effectue avec la touche <Tab>.
In [28
]: r.<
TAB>
r.__add__
r.__iadd__
r.__setattr__
r.__class__
r.__imul__
r.__setitem__
r.__contains__
r.__init__
r.__setslice__
r.__delattr__
r.__iter__
r.__sizeof__
r.__delitem__
r.__le__
r.__str__
r.__delslice__
r.__len__
r.__subclasshook__
r.__doc__
r.__lt__
r.append
r.__eq__
r.__mul__
r.count
r.__format__ r.__ne__
r.extend
r.__ge__
r.__new__
r.index
r.__getattribute__
r.__reduce__
r.insert
r.__getitem__
r.__reduce_ex__ r.pop
r.__getslice__
r.__repr__
r.remove
r.__gt__
r.__reversed__ r.reverse
r.__hash__
r.__rmul__
r.sort
II-B-2. Strings / Chaînes de caractères▲
Différentes syntaxes possibles (guillemets anglais simples ou doubles, éventuellement triplés) :
s =
'Hello, how are you?'
s =
"Hi, what's up"
s =
'''Hello, # tripling the quotes allows the
how are you'''
# the string to span more than one line
s =
"""Hi,
what's up?"""
In [1
]: 'Hi, what'
s up?'
------------------------------------------------------------
File "<ipython console>", line 1
'
Hi, what's up?'
^
SyntaxError
: invalid syntax
Le caractère de saut de ligne est \n et celui de tabulation est \t.
Les chaînes de caractères (strings) constituent un jeu de données au même titre que les listes. Aussi peuvent-elles être indexées et échantillonnées, en utilisant les mêmes syntaxes et règles.
Indexation :
>>>
a =
"hello"
>>>
a[0
]
'h'
>>>
a[1
]
'e'
>>>
a[-
1
]
'o'
Rappelez-vous que l'utilisation d'indice négatif permet de compter à partir de la fin.
Échantillonnage (slicing) :
>>>
a =
"hello, world!"
>>>
a[3
:6
] # 3rd to 6th (excluded) elements: elements 3, 4, 5
'lo,'
>>>
a[2
:10
:2
] # Syntax: a[start:stop:step]
'lo o'
>>>
a[::3
] # every three characters, from beginning to end
'hl r!'
Les accents et les caractères spéciaux sont compris dans l'Unicode (voir http://docs.python.org/tutorial/introduction.html#unicode-strings).
Une chaîne de caractères (string) est un objet immuable et il n'est pas possible de modifier son contenu. On peut cependant créer un nouveau string à partir d'un objet existant.
In [53
]: a =
"hello, world!"
In [54
]: a[2
] =
'z'
---------------------------------------------------------------------------
Traceback (
most recent call last):
File "<stdin>"
, line 1
, in
<
module>
TypeError
: 'str'
object does not
support item assignment
In [55
]: a.replace
(
'l'
, 'z'
, 1
)
Out[55
]: 'hezlo, world!'
In [56
]: a.replace
(
'l'
, 'z'
)
Out[56
]: 'hezzo, worzd!'
Les strings possèdent de nombreuses méthodes fortes utiles comme a.replace tel que vu ci-dessus. Rappelez-vous que a. est une notion POOhttp://hdd34.developpez.com/cours/artpoo/ et utilisez la complétion par tabulation ou help(r) pour connaître les autres méthodes.
Python offre des possibilités évoluées pour manipuler les chaînes de caractères, la recherche de motifs (pattern) ou encore le formatage. Pour les plus passionnés, référez-vous à :
http://docs.python.org/library/stdtypes.html#string-methods
http://docs.python.org/library/string.html#new-string-formatting
Formatage de chaînes de caractères:
>>>
'An integer:
%i
; a float:
%f
; another string:
%s
'
%
(
1
, 0.1
, 'string'
)
'An integer: 1; a float: 0.100000; another string: string'
>>>
i =
102
>>>
filename =
'processing_of_dataset_
%d
.txt'
%
i
>>>
filename
'processing_of_dataset_102.txt'
II-B-3. Dictionnaires▲
Un dictionnaire est basiquement un tableau associatif qui connecte ensemble des clés à des valeurs. C'est un conteneur non ordonné.
>>>
tel =
{'emmanuelle'
: 5752
, 'sebastian'
: 5578
}
>>>
tel['francis'
] =
5915
>>>
tel
{'sebastian'
: 5578
, 'francis'
: 5915
, 'emmanuelle'
: 5752
}
>>>
tel['sebastian'
]
5578
>>>
tel.keys
(
)
['sebastian'
, 'francis'
, 'emmanuelle'
]
>>>
tel.values
(
)
[5578
, 5915
, 5752
]
>>>
'francis'
in
tel
True
Il peut être utilisé pour stocker/rechercher de manière pratique des valeurs associées à un nom (un string pour une date, un nom...).
Consultez http://docs.python.org/tutorial/datastructures.html#dictionaries pour plus d'informations.
Un dictionnaire peut avoir des clés de différents types :
>>>
d =
{'a'
:1
, 'b'
:2
, 3
:'hello'
}
>>>
d
{'a'
: 1
, 3
: 'hello'
, 'b'
: 2
}
Quelques conteneurs supplémentaires.
TUPLES
Les tupleshttp://python.developpez.com/cours/DiveIntoPython/php/frdiveintopython/native_data_types/tuples.php sont des listes immuables. Les éléments d'un tuple s'écrivent entre parenthèses, ou juste séparés par des virgules :
>>>
t =
12345
, 54321
, 'hello!'
>>>
t[0
]
12345
>>>
t
(
12345
, 54321
, 'hello!'
)
>>>
u =
(
0
, 2
)
SETS
Ensemble non ordonné, éléments uniques :
>>>
s =
set((
'a'
, 'b'
, 'c'
, 'a'
))
>>>
s
set(
['a'
, 'c'
, 'b'
])
>>>
s.difference
((
'a'
, 'b'
))
set(
['c'
])
Les opérateurs d'assignation
La librairie de référence Pythonhttp://docs.python.org/reference/simple_stmts.html#assignment-statements indique que : les déclarations d'affectations sont utilisées pour (re)nommer des valeurs et modifier les attributs ou les éléments d'un objet mutable.
En clair, cela fonctionne comme suit (simple assignation) :
1- L'expression à droite est analysée, puis l'objet correspondant est créé ou récupéré.
2- Le nom donné à gauche est affecté à l'objet de l'étape 1.
Veuillez noter que :
- un objet peut avoir plusieurs références rattachées ;
In [1
]: a =
[1
, 2
, 3
]
In [2
]: b =
a
In [3
]: a
Out[3
]: [1
, 2
, 3
]
In [4
]: b
Out[4
]: [1
, 2
, 3
]
In [5
]: a is
b
Out[5
]: True
In [6
]: b[1
] =
'hi!'
In [7
]: a
Out[7
]: [1
, 'hi!'
, 3
]
- pour modifier tout ou partie d'une liste, utilisez l'indexation ou l'échantillonnage :
In [1
]: a =
[1
, 2
, 3
]
In [3
]: a
Out[3
]: [1
, 2
, 3
]
In [4
]: a =
['a'
, 'b'
, 'c'
] # Creates another object.
In [5
]: a
Out[5
]: ['a'
, 'b'
, 'c'
]
In [6
]: id(
a)
Out[6
]: 138641676
In [7
]: a[:] =
[1
, 2
, 3
] # Modifies object in place.
In [8
]: a
Out[8
]: [1
, 2
, 3
]
In [9
]: id(
a)
Out[9
]: 138641676
# Same as in Out[6], yours will differ...
Le concept de clé ici est mutable vs immuable :
- Les objets mutables peuvent être modifiés à la volée.
- Les objets immuables ne peuvent être modifiés une fois créés.
Une très bonne explication, très détaillée, sur le cas ci-dessus peut être lu dans un article de David M. BEAZLEYhttp://www.informit.com/articles/article.aspx?p=453682
III. Contrôle de flux▲
Cela permet de contrôler l'ordre dans lequel le code va s'exécuter.
III-A. if/elif/else▲
>>>
if
2
**
2
==
4
:
... print
'Obvious!'
...
Obvious!
Les blocs de code sont délimités par l'indentation.
Saisissez les lignes suivantes dans votre interpréteur Python, et prenez garde à bien respecter l'indentation. Le shell IPython augmente automatiquement l'indentation après le caractère ":" ; pour diminuer l'indentation, pressez 4 fois la touche <backspace>. Appuyez sur <Entrée> deux fois pour quitter le bloc logique de code.
In [1
]: a =
10
In [2
]: if
a ==
1
:
...: print
(
1
)
...: elif
a ==
2
:
...: print
(
2
)
...: else
:
...: print
(
'A lot'
)
...:
A lot
L'indentation est obligatoire dans les scripts. Afin de vous exercer un peu, ressaisissez les lignes précédentes, avec la même indentation dans un script que vous nommerez condition.py et exécutez-le avec la commande run condition.py dans IPython.
III-B. for/range▲
Itération avec un index :
>>>
for
i in
range(
4
):
... print
(
i)
0
1
2
3
Mais le plus souvent, il est plus pratique et plus lisible d'itérer sur les valeurs :
III-C. while/break/continue▲
On utilise le style de boucle while typique au C (problème de Mandelbrot) :
>>>
z =
1
+
1
j
>>>
while
abs(
z) <
100
:
... z =
z**
2
+
1
>>>
z
(-
134
+
352
j)
Allons un peu plus loin
break permet de sortir d'une boucle for/while :
>>>
z =
1
+
1
j
>>>
while
abs(
z) <
100
:
... if
z.imag ==
0
:
... break
... z =
z**
2
+
1
continue permet de sauter à l'itération suivante :
>>>
a =
[1
, 0
, 2
, 4
]
>>>
for
element in
a:
... if
element ==
0
:
... continue
... print
1.
/
element
1.0
0.5
0.25
expressions conditionnelles :
If <objet> : |
Évalue à False :
|
a == b : |
Test d'égalité, avec logique : Sélectionnez
|
a is b : |
Test d'identité : il doit s'agir du même objet des deux côtés : Sélectionnez
|
a in b : |
Pour n'importe quel ensemble b : b contient a. Sélectionnez
|
III-D. itérations avancées▲
III-D-1. Itération de n'importe quelle séquence▲
Vous pouvez itérer n'importe quel type d'objet (string, liste, clés de dictionnaire, ligne de fichier…) :
>>>
vowels =
'aeiouy'
>>>
for
i in
'powerful'
:
... if
i in
vowels:
... print
(
i),
o e u
>>>
message =
"Hello how are you?"
>>>
message.split
(
) # returns a list
['Hello'
, 'how'
, 'are'
, 'you?'
]
>>>
for
word in
message.split
(
):
... print
word
...
Hello
how
are
you?
Peu de langages (particulièrement les langages à but scientifique) permettent de boucler sur autre chose que des entiers ou des indices. Avec Python, il est possible de boucler sur ce qui vous intéresse sans vous soucier des indices qui ne vous intéressent pas. Cela permet souvent d'obtenir du code plus lisible.
Il n'est pas recommandé de modifier la séquence que vous êtes en train d'itérer.
III-D-2. Garder une trace de l'index▲
Une des tâches classiques est d'itérer une séquence tout en gardant en mémoire le numéro de l'élément.
Vous pouvez utiliser une boucle while avec un compteur. Ou une boucle for :
>>>
words =
(
'cool'
, 'powerful'
, 'readable'
)
>>>
for
i in
range(
0
, len(
words)):
... print
i, words[i]
0
cool
1
powerful
2
readable
Mais Python fournit le mot clé enumerate pour cela :
>>>
for
index, item in
enumerate(
words):
... print
index, item
0
cool
1
powerful
2
readable
III-D-3. Boucler sur un dictionnaire▲
Utilisez iteritems :
>>>
d =
{'a'
: 1
, 'b'
:1.2
, 'c'
:1
j}
>>>
for
key, val in
d.iteritems
(
):
... print
(
'Key:
%s
has value:
%s
'
%
(
key, val))
Key: a has value: 1
Key: c has value: 1
j
Key: b has value: 1.2
III-E. Liste en compréhension▲
>>>
[i**
2
for
i in
range(
4
)]
[0
, 1
, 4
, 9
]
III-F. Exercice▲
Calculez la décimale de pi en utilisant la formule de Wallis :
IV. Définir des fonctions▲
IV-A. Définition de fonctions▲
In [56
]: def
test
(
):
....: print
(
'in test function'
)
....:
....:
In [57
]: test
(
)
in
test function
Les blocs de code des fonctions doivent être indentés au même titre que les blocs de contrôle de flux.
IV-B. Effectuer un retour▲
Les fonctions peuvent potentiellement retourner des valeurs.
In [6
]: def
disk_area
(
radius):
...: return
3.14
*
radius *
radius
...:
In [8
]: disk_area
(
1.5
)
Out[8
]: 7.0649999999999995
À défaut, les fonctions retournent None.
Veuillez noter la syntaxe pour créer une fonction :
- le mot clé def ;
- ce mot clé est suivi par le nom de la fonction ;
- les arguments d'une fonction sont passés entre parenthèses, et suivi de « : » ;
- le corps de la fonction ;
- un return object pour potentiellement renvoyer des valeurs.
IV-C. Les paramètres▲
Paramètres obligatoires (arguments de positionnement) :
In [81
]: def
double_it
(
x):
....: return
x *
2
....:
In [82
]: double_it
(
3
)
Out[82
]: 6
In [83
]: double_it
(
)
---------------------------------------------------------------------------
Traceback (
most recent call last):
File "<stdin>"
, line 1
, in
<
module>
TypeError
: double_it
(
) takes exactly 1
argument (
0
given)
Paramètres optionnels (mots clés ou arguments nommés) :
In [84
]: def
double_it
(
x=
2
):
....: return
x *
2
....:
In [85
]: double_it
(
)
Out[85
]: 4
In [86
]: double_it
(
3
)
Out[86
]: 6
Les mots clés vous permettent de définir des valeurs par défaut.
Les valeurs par défaut sont à communiquer quand la fonction est définie, et non quand elle est appelée. Cela peut être d'autant plus problématique quand on utilise des types mutables (c'est-à-dire des dictionnaires ou des listes par exemple) et qu'on les modifie dans le corps de la fonction, puisque les modifications se propageront au-delà de l'appel de la fonction.
Utilisation d'un type immuable comme mot argument mot clé :
In [124
]: bigx =
10
In [125
]: def
double_it
(
x=
bigx):
.....: return
x *
2
.....:
In [126
]: bigx =
1e9
# Now really big
In [128
]: double_it
(
)
Out[128
]: 20
Utilisation d'un type mutable comme argument mot clé (et modification de ce dernier dans le corps de la fonction) :
In [2
]: def
add_to_dict
(
args=
{'a'
: 1
, 'b'
: 2
}):
...: for
i in
args.keys
(
):
...: args[i] +=
1
...: print
args
...:
In [3
]: add_to_dict
Out[3
]: <
function __main__.add_to_dict>
In [4
]: add_to_dict
(
)
{'a'
: 2
, 'b'
: 3
}
In [5
]: add_to_dict
(
)
{'a'
: 3
, 'b'
: 4
}
In [6
]: add_to_dict
(
)
{'a'
: 4
, 'b'
: 5
}
Exemples plus complexes de la mise en œuvre de l'échantillonnage en Python :
In [98
]: def
slicer
(
seq, start=
None
, stop=
None
, step=
None
):
....: """Implement basic python slicing."""
....: return
seq[start:stop:step]
....:
In [101
]: rhyme =
'one fish, two fish, red fish, blue fish'
.split
(
)
In [102
]: rhyme
Out[102
]: ['one'
, 'fish,'
, 'two'
, 'fish,'
, 'red'
, 'fish,'
, 'blue'
, 'fish'
]
In [103
]: slicer
(
rhyme)
Out[103
]: ['one'
, 'fish,'
, 'two'
, 'fish,'
, 'red'
, 'fish,'
, 'blue'
, 'fish'
]
In [104
]: slicer
(
rhyme, step=
2
)
Out[104
]: ['one'
, 'two'
, 'red'
, 'blue'
]
In [105
]: slicer
(
rhyme, 1
, step=
2
)
Out[105
]: ['fish,'
, 'fish,'
, 'fish,'
, 'fish'
]
In [106
]: slicer
(
rhyme, start=
1
, stop=
4
, step=
2
)
Out[106
]: ['fish,'
, 'fish,'
]
L'ordre des mots clés, en tant qu'arguments, importe peu :
In [107
]: slicer
(
rhyme, step=
2
, start=
1
, stop=
4
)
Out[107
]: ['fish,'
, 'fish,'
]
Mais il est considéré comme bonne pratique de garder le même ordre que dans la définition de la fonction.
Les mots clés comme arguments sont très pratiques afin de définir des fonctions avec un nombre variable d'arguments quand les valeurs par défaut doivent être utilisées dans la plupart des appels.
IV-D. Transmettre une valeur▲
Pouvons-nous modifier la valeur d'une variable à l'intérieur d'une fonction ? La plupart des langages (C, Java…) distinguent « passage par valeur » et « passage par référence ». En Python, une telle distinction est un peu superficielle, et il est subtil de savoir si vos variables vont être modifiées ou non. Heureusement, il existe des règles claires.
Les paramètres de fonctions sont liés à des objets, lesquels sont passés par valeur. Quand vous passez une variable à une fonction, Python communique la référence à l'objet auquel la variable se réfère, pas la variable elle-même. Si la valeur passée dans une fonction est immuable, la fonction ne modifie pas la variable de l'appelant. Si la variable est mutable, la fonction peut modifier la variable de l'appelant.
>>>
def
try_to_modify
(
x, y, z):
... x =
23
... y.append
(
42
)
... z =
[99
] # new reference
... print
(
x)
... print
(
y)
... print
(
z)
...
>>>
a =
77
# immutable variable
>>>
b =
[99
] # mutable variable
>>>
c =
[28
]
>>>
try_to_modify
(
a, b, c)
23
[99
, 42
]
[99
]
>>>
print
(
a)
77
>>>
print
(
b)
[99
, 42
]
>>>
print
(
c)
[28
]
Les fonctions possèdent une table de variables locales appelées « espace de nom local ».
La variable x existe seulement à l'intérieur de la fonction try_to_modify().
IV-E. Les variables globales▲
Les variables déclarées en dehors de la fonction peuvent être référencées à l'intérieur de la fonction :
In [114
]: x =
5
In [115
]: def
addx
(
y):
.....: return
x +
y
.....:
In [116
]: addx
(
10
)
Out[116
]: 15
Mais ces variables globales ne peuvent être modifiées à l'intérieur des fonctions, à moins de les déclarer comme globales (mot clé global) dans la fonction.
Ce qui suit ne fonctionne pas :
In [117
]: def
setx
(
y):
.....: x =
y
.....: print
(
'x is
%d
'
%
x)
.....:
.....:
In [118
]: setx
(
10
)
x is
10
In [120
]: x
Out[120
]: 5
Ceci, par contre, fonctionne :
In [121
]: def
setx
(
y):
.....: global
x
.....: x =
y
.....: print
(
'x is
%d
'
%
x)
.....:
.....:
In [122
]: setx
(
10
)
x is
10
In [123
]: x
Out[123
]: 10
IV-F. Nombres variables de paramètres▲
Forme des paramètres :
- *args : n'importe quel nombre d'arguments de position sous forme de tuple ;
- **kwargs : n'importe quel nombre d'arguments nommés (mots clés) sous forme de dictionnaire.
In [35
]: def
variable_args
(*
args, **
kwargs):
....: print
'args is'
, args
....: print
'kwargs is'
, kwargs
....:
In [36
]: variable_args
(
'one'
, 'two'
, x=
1
, y=
2
, z=
3
)
args is
(
'one'
, 'two'
)
kwargs is
{'y'
: 2
, 'x'
: 1
, 'z'
: 3
}
IV-G. Les docstrings▲
Il s'agit de la documentation concernant ce que fait la fonction et ses paramètres. Voici la convention générale :
In [67
]: def
funcname
(
params):
....: """Concise one-line sentence describing the function.
...
.:
...
.: Extended summary which can contain multiple paragraphs.
...
.: """
...
.: # function body
...
.: pass
...
.:
In [68]: funcname?
Type: function
Base Class: type 'function'>
String Form: <function funcname at 0xeaa0f0>
Namespace: Interactive
File: <ipython console>
Definition: funcname(params)
Docstring:
Concise one-line sentence describing the function.
Extended summary which can contain multiple paragraphs.
Guide sur les docstrings
Dans un but de standardisation, la page de Convention des docstringshttp://legacy.python.org/dev/peps/pep-0257/ documente la sémantique et les conventions concernant les docstrings Python.
Aussi, les modules Numpy et Scipy ont défini un standard précis pour la documentation des fonctions scientifiques, que vous devrez peut-être suivre pour vos propres fonctions avec une section Parameters, une section Examples…
IV-H. Les fonctions sont des objets▲
Les fonctions sont des objets multitâches, ce qui signifie qu'elles peuvent être :
- assignées à une variable ;
- un élément de liste (ou de tout autre collection) ;
- passées comme argument à une autre fonction.
In [38
]: va =
variable_args
In [39
]: va
(
'three'
, x=
1
, y=
2
)
args is
(
'three'
,)
kwargs is
{'y'
: 2
, 'x'
: 1
}
IV-I. Les méthodes▲
Les méthodes sont des fonctions attachées à des objets. Vous avez déjà pu le constater dans nos exemples sur les listes, les dictionnaires, les chaînes de caractères…
IV-J. Exercice : Suite de Fibonacci▲
Écrire une fonction qui affiche les n premiers éléments de la suite de Fibonacci, définie par :
IV-K. Exercice : Tri rapide▲
Implémenter un algorithme de tri rapide, tel que défini sur wikipediahttp://fr.wikipedia.org/wiki/Algorithme :
function quicksort(array)
var list less, greater if length(array) < 2
return array
select and remove a pivot value pivot from array for each x in array
if x < pivot + 1 then append x to less else append x to greater
return concatenate(quicksort(less), pivot, quicksort(greater))
V. Réutilisation de code : scripts et modules▲
Jusqu'à présent, nous avons saisi l'intégralité de nos instructions directement dans l'interpréteur. Pour des jeux d'instructions plus longs, il nous faut changer de direction et écrire le code dans des fichiers texte (avec un éditeur de texte), ce que nous appellerons « scripts » ou encore « modules ». Utilisez votre éditeur de texte préféré (peut-être propose-t-il aussi la coloration syntaxique Python), ou l'éditeur fourni avec la Scientific Python Suite que vous utilisez peut-être (par exemple, Scite avec Python(x,y)).
V-A. Les scripts▲
Pour commencer, écrivons un script, c'est un fichier avec une suite d'instructions qui sont exécutées chaque fois que le script est appelé.
Les instructions peuvent être par exemple copiées-collées depuis l'interpréteur (mais attention à respecter l'indentation).
L'extension des fichiers Python est .py. Écrivez ou copiez-collez les lignes suivantes dans un fichier test.py :
message =
"Hello how are you?"
for
word in
message.split
(
):
print
word
Maintenant, exécutons ce script de manière interactive, à l'intérieur de l'interpréteur IPython. Ce doit être l'utilisation la plus classique dans la recherche scientifique.
Dans IPython, la syntaxe pour exécuter un script est %run script.py. Par exemple :
In [1
]: %
run test.py
Hello
how
are
you?
In [2
]: message
Out[2
]: 'Hello how are you?'
Le script a été exécuté. De plus, les variables définies dans le script (comme message) sont maintenant disponibles dans l'espace de nom de l'interpréteur.
Les autres interpréteurs offrent également la possibilité d'exécuter des scripts (par exemple, execfile dans l'interpréteur Python).
Il est également possible d'exécuter ce script comme un programme standalone, en lançant ce script à l'intérieur d'un terminal shell(console Linux/Mac, ou cmd pour Windows). Par exemple, si nous sommes dans le même dossier que notre script, nous pouvons exécuter les lignes suivantes dans une console :
$ python test.py
Hello
how
are
you?
Les scripts standalone peuvent également prendre des arguments. Ainsi, dans file.py :
import
sys
print
sys.argv
$ python file.py test arguments
['file.py'
, 'test'
, 'arguments'
]
N'essayez pas d'implémenter par vous-même un parsing. Utilisez les modules standards optparsehttps://docs.python.org/2/library/optparse.html, argparsehttps://docs.python.org/dev/library/argparse.html ou docopthttp://docopt.org/.
V-B. Importer des objets depuis des modules▲
In [1
]: import
os
In [2
]: os
Out[2
]: <
module 'os'
from
'/usr/lib/python2.6/os.pyc'
>
In [3
]: os.listdir
(
'.'
)
Out[3
]:
['conf.py'
,
'basic_types.rst'
,
'control_flow.rst'
,
'functions.rst'
,
'python_language.rst'
,
'reusing.rst'
,
'file_io.rst'
,
'exceptions.rst'
,
'workflow.rst'
,
'index.rst'
]
Et aussi :
In [4
]: from
os import
listdir
Import rapide :
In [5
]: import
numpy as
np
from
os import
*
Ceci s'appelle le star import. Veuillez l'employer avec précaution.
- Cela peut rendre le code difficile à lire et à comprendre : d'où viennent précisément les divers symboles ?
- Cela peut rendre impossible à deviner une fonctionnalité dans un contexte.
- Cela peut restreindre les noms des variables que vous pouvez utiliser : os.name peut surcharger name et vice-versa.
- La création de nom peut poser problème entre modules.
- Cela peut rendre le code très difficile à déboguer.
Les modules sont également une bonne façon d'organiser son code de manière hiérarchique. Actuellement, tous les outils scientifiques utilisent des modules :
>>>
import
numpy as
np # data arrays
>>>
np.linspace
(
0
, 10
, 6
)
array
(
[ 0.
, 2.
, 4.
, 6.
, 8.
, 10.
])
>>>
import
scipy # scientific computing
Avec Python(x,y), Ipython(x,y) exécutez les imports suivants au démarrage :
>>>
import
numpy
>>>
import
numpy as
np
>>>
from
pylab import
*
>>>
import
scipy
Et il ne sera plus nécessaire de réimporter ces modules.
V-C. Créer des modules▲
Si nous voulons créer des programmes plus importants et mieux structurés (en comparaison à de simples scripts), avec quelques définitions d'objets (variables, fonctions, classes) et que nous désirions les réutiliser de temps à autre, nous devons créer des modules.
Nous allons créer un module demo, dans un fichier demo.py :
"A demo module."
def
print_b
(
):
"Prints b."
print
'b'
def
print_a
(
):
"Prints a."
print
'a'
c =
2
d =
2
Dans ce fichier, nous définissons deux fonctions print_a et print_b. Supposons que nous voulions appeler la fonction print_a depuis l'interpréteur. Nous pourrions exécuter le fichier comme un script, mais puisque nous voulons juste accéder à la fonction print_a, nous devons plutôt l'importer comme un module. La syntaxe est la suivante :
In [1
]: import
demo
In [2
]: demo.print_a
(
)
a
In [3
]: demo.print_b
(
)
b
Importer le module donne accès à ses objets, en utilisant la syntaxe module.objet. N'oubliez pas de mettre le nom du module avant le nom de l'objet, autrement Python ne reconnaîtra pas l'instruction.
V-C-1. Introspection▲
In [4
]: demo?
Type: module
Base Class: <
type 'module'
>
String Form: <
module 'demo'
from
'demo.py'
>
Namespace: Interactive
File: /
home/
varoquau/
Projects/
Python_talks/
scipy_2009_tutorial/
source/
demo.py
Docstring:
A demo module.
In [5
]: who
demo
In [6
]: whos
Variable Type Data/
Info
------------------------------
demo module <
module 'demo'
from
'demo.py'
>
In [7
]: dir(
demo)
Out[7
]:
['__builtins__'
,
'__doc__'
,
'__file__'
,
'__name__'
,
'__package__'
,
'c'
,
'd'
,
'print_a'
,
'print_b'
]
In [8
]: demo.
demo.__builtins__
demo.__init__
demo.__str__
demo.__class__
demo.__name__
demo.__subclasshook__
demo.__delattr__
demo.__new__
demo.c
demo.__dict__
demo.__package__ demo.d
demo.__doc__
demo.__reduce__
demo.print_a
demo.__file__
demo.__reduce_ex__ demo.print_b
demo.__format__ demo.__repr__
demo.py
demo.__getattribute__
demo.__setattr__
demo.pyc
demo.__hash__
demo.__sizeof__
V-C-2. Import d'objet dans l'espace de nom principal▲
In [9
]: from
demo import
print_a, print_b
In [10
]: whos
Variable Type Data/
Info
--------------------------------
demo module <
module 'demo'
from
'demo.py'
>
print_a function <
function print_a at 0xb7421534
>
print_b function <
function print_b at 0xb74214c4
>
In [11
]: print_a
(
)
a
Module mis en cache
Les modules sont mis en cache. Si vous modifiez demo.py, puis le réimportez dans la session précédente, vous conserverez l'ancienne version.
Solution :
In [10
]: reload(
demo)
V-D. '__main__' et chargement de modules▲
Fichier demo2.py :
import
sys
def
print_a
(
):
"Prints a."
print
'a'
print
sys.argv
if
__name__
==
'__main__'
:
print_a
(
)
import :
In [11
]: import
demo2
b
In [12
]: import
demo2
Lancement :
In [13
]: %
run demo2
b
a
V-E. Scripts ou modules : Comment organiser votre code ?▲
Règles de base
- Les jeux d'instructions qui sont appelés plusieurs fois devraient être écrits à l'intérieur de fonctions pour plus de réutilisabilité.
- Les fonctions (ou tout autre morceau de code) qui sont appelées depuis plusieurs modules différents devraient être écrites à l'intérieur de module, ainsi seul le module est importé dans les différents scripts (ne copiez-collez pas vos fonctions dans les différents scripts).
V-E-1. Comment les modules sont trouvés et importés▲
Quand import mymodule est exécuté, le module mymodule est recherché dans une liste donnée de répertoire. Cette liste inclue une liste des dépendances par défaut (par exemple, /usr/lib/python sous Linux), ainsi qu'une liste de répertoires spécifiés dans la variable d'environnement PYTHONPATH.
La liste de ces dossiers recherchés par Python est fournie par la variable sys.path :
In [1
]: import
sys
In [2
]: sys.path
Out[2
]:
[''
,
'/home/varoquau/.local/bin'
,
'/usr/lib/python2.7'
,
'/home/varoquau/.local/lib/python2.7/site-packages'
,
'/usr/lib/python2.7/dist-packages'
,
'/usr/local/lib/python2.7/dist-packages'
,
...]
Les modules doivent être présents dans le chemin de recherche, aussi vous pouvez :
- écrire vos propres modules à l'intérieur de dossiers déjà définis dans le chemin de recherche (par exemple, $HOME/.local/lib/python2.7/dist-packages). Vous pouvez utiliser des liens symboliques (sous Linux) pour stocker votre code ailleurs ;
- modifier la variable d'environnement PYTHONPATH pour inclure les dossiers contenant les modules définis par l'utilisateur.
Sur Linux/Unix, ajoutez la ligne suivante à un fichier lu par le shell au démarrage (ex. /etc/profile, ou .profile).
export PYTHONPATH
=
$PYTHONPATH
:/home/emma/user_defined_modules
Sous Windows, http://support.microsoft.com/kb/310519 explique comment configurer sa variable d'environnement.
- ou modifier le sys.path lui-même à l'intérieur d'un script Python.
import
sys
new_path =
'/home/emma/user_defined_modules'
if
new_path not
in
sys.path:
sys.path.append
(
new_path)
Cette dernière méthode n'est pas très robuste ; de plus elle rend le code moins portable et vous devez redéfinir la variable chaque fois que vous désirez importer un module dans ce dossier.
Consultez http://docs.python.org/tutorial/modules.html pour plus d'informations.
V-F. Les packages▲
Un dossier qui contient plusieurs modules est appelé un paquetage (package). Un package peut contenir d'autres packages. Un fichier spécial, __init__.py (qui peut être vide) indique à Python que le dossier est un package Python, à partir duquel les modules peuvent être importés.
$ ls
cluster/
io/
README.txt@ stsci/
__config__.py@ LATEST.txt@ setup.py@ __svn_version__.py@
__config__.pyc lib/
setup.pyc __svn_version__.pyc
constants/
linalg/
setupscons.py@ THANKS.txt@
fftpack/
linsolve/
setupscons.pyc TOCHANGE.txt@
__init__
.py@ maxentropy/
signal/
version.py@
__init__
.pyc misc/
sparse/
version.pyc
INSTALL.txt@ ndimage/
spatial/
weave/
integrate/
odr/
special/
interpolate/
optimize/
stats/
$ cd ndimage
$ ls
doccer.py@ fourier.pyc interpolation.py@ morphology.pyc setup.pyc
doccer.pyc info.py@ interpolation.pyc _nd_image.so
setupscons.py@
filters.py@ info.pyc measurements.py@ _ni_support.py@
setupscons.pyc
filters.pyc __init__
.py@ measurements.pyc _ni_support.pyc tests/
fourier.py@ __init__
.pyc morphology.py@ setup.py@
Avec IPython :
In [1
]: import
scipy
In [2
]: scipy.__file__
Out[2
]: '/usr/lib/python2.6/dist-packages/scipy/__init__.pyc'
In [3
]: import
scipy.version
In [4
]: scipy.version.version
Out[4
]: '0.7.0'
In [5
]: import
scipy.ndimage.morphology
In [6
]: from
scipy.ndimage import
morphology
In [17
]: morphology.binary_dilation?
Type: function
Base Class: <
type 'function'
>
String Form: <
function binary_dilation at 0x9bedd84
>
Namespace: Interactive
File: /
usr/
lib/
python2.6
/
dist-
packages/
scipy/
ndimage/
morphology.py
Definition: morphology.binary_dilation
(
input, structure=
None
,
iterations=
1
, mask=
None
, output=
None
, border_value=
0
, origin=
0
,
brute_force=
False
)
Docstring:
Multi-
dimensional binary dilation with
the given structure.
An output array can optionally be provided. The origin parameter
controls the placement of the filter. If no structuring element is
provided an element is
generated with
a squared connectivity equal
to one. The dilation operation is
repeated iterations times. If
iterations is
less than 1
, the dilation is
repeated until the
result does not
change anymore. If a mask is
given, only those
elements with
a true value at the corresponding mask element are
modified at each iteration.
V-G. Bonnes pratiques▲
- Utilisez des noms significatifs pour les objets.
- Utilisez l'indentation : aucune autre possibilité !
L'indentation est incontournable en Python ! Chaque bloc de commande se distingue du précédent par un niveau d'indentation supplémentaire.
Il doit obligatoirement en avoir après def f(): ou encore while:. À la fin de chacun de ces blocs, on doit décrémenter cette indentation d'un niveau (et le ré-augmenter si nouveau bloc).
Le respect strict de l'indentation est le prix à payer pour éviter d'avoir à utiliser des { et des ; qui délimitent les blocs logiques dans d'autres langages. Toute erreur d'indentations lève une exception :
------------------------------------------------------------
IndentationError
: unexpected indent (
test.py, line 2
)
Cette histoire d'indentation peut paraître un peu déroutante au début. Cependant, la clarté de l'indentation et l'absence de caractères superflus permettent d'obtenir un code agréable à lire comparé à d'autres langages.
- Niveau d'indentation
À l'intérieur de votre éditeur de texte, vous pouvez choisir d'indenter avec n'importe quel nombre d'espaces (1,2,3,4…). Cependant, il est couramment admis d'indenter de quatre espaces. Vous pouvez ainsi paramétrer votre éditeur pour que la touche <Tab> corresponde à quatre espaces. Avec Python(x,y), l'éditeur est déjà préconfiguré.
- Mise en forme
Lignes trop longues : vous ne devriez pas écrire de très longues lignes qui dépassent les 80 caractères. Les lignes trop longues peuvent être coupées avec le caractère backslash \ immédiatement suivi d'un saut à la ligne :
>>>
long_line =
"Here is a very very long line \
... that we break in two parts."
Note du traducteur : la PEP8 autorise maintenant de monter jusqu'à 100 caractères.
Espaces : placez des espaces après les virgules, autour des opérateurs arithmétiques…
>>>
a =
1
# yes
>>>
a=
1
# too cramped
Un certain nombre de règles d'écriture pour obtenir un code plus « agréable » (et plus) sont disponibles dans http://www.python.org/dev/peps/pep-0008.
Pour aller plus vite
Si vous désirez faire une première passe rapide sur l'écosystème de Scipy, vous pouvez d'ores et déjà passer au chapitre suivant :
http://scipy-lectures.github.io/intro/numpy/index.html#numpy
Le reste de ce chapitre n'est pas nécessaire pour comprendre Scipy. Cependant, n'oubliez pas de revenir et de finir ce chapitre plus tard.
VI. Entrées et sorties▲
Afin d'être exhaustif, voici quelques informations concernant les entrées et sorties avec Python. Puisque nous utiliserons les méthodes Numpy pour lire et écrire des fichiers, vous pouvez sauter ce chapitre si vous le désirez.
Nous écrivons ou lisons des chaînes de caractères vers/depuis des fichiers (n'importe quel type de donnée peut être converti en strings). Pour écrire dans un fichier :
>>>
f =
open(
'workfile'
, 'w'
) # opens the workfile file
>>>
type(
f)
<
type 'file'
>
>>>
f.write
(
'This is a test
\n
and another test'
)
>>>
f.close
(
)
Pour lire un fichier :
In [1
]: f =
open(
'workfile'
, 'r'
)
In [2
]: s =
f.read
(
)
In [3
]: print
(
s)
This is
a test
and
another test
In [4
]: f.close
(
)
Pour plus de détails : http://docs.python.org/tutorial/inputoutput.html
Itérer depuis un fichier :
In [6
]: f =
open(
'workfile'
, 'r'
)
In [7
]: for
line in
f:
...: print
line
...:
This is
a test
and
another test
In [8
]: f.close
(
)
VI-A. Modes de fichiers▲
- Lecture seule : 'r'
-
Écriture seule : 'w'
- Note : permet de créer un nouveau fichier ou écrase un fichier existant.
- Écrire à la suite d'un fichier : 'a'
- Lire et écrire : 'r+'
-
Travailler en mode binaire : 'b'
- Note : spécialement pour Windows.
VII. La librairie standard▲
Les documents de référence pour cette section sont :
- la documentation de la librairie standard Python : http://docs.python.org/library/index.htmlhttp://docs.python.org/library/index.html ;
- Python Essential Reference, de David BEAZLEY, professionnel chez Addison-Wesley.
VII-A. Module OS : Fonctionnalité de l'OS▲
« Un moyen simple d'accéder aux fonctionnalités spécifiques d'un système d'exploitation. »
VII-A-1. Manipulation de fichiers et de dossiers▲
Dossier courant :
In [17
]: os.getcwd
(
)
Out[17
]: '/Users/cburns/src/scipy2009/scipy_2009_tutorial/source'
Lister le contenu d'un dossier :
In [31
]: os.listdir
(
os.curdir)
Out[31
]:
['.index.rst.swo'
,
'.python_language.rst.swp'
,
'.view_array.py.swp'
,
'_static'
,
'_templates'
,
'basic_types.rst'
,
'conf.py'
,
'control_flow.rst'
,
'debugging.rst'
,
...
Créer un dossier :
In [32
]: os.mkdir
(
'junkdir'
)
In [33
]: 'junkdir'
in
os.listdir
(
os.curdir)
Out[33
]: True
Renommer un dossier :
In [36
]: os.rename
(
'junkdir'
, 'foodir'
)
In [37
]: 'junkdir'
in
os.listdir
(
os.curdir)
Out[37
]: False
In [38
]: 'foodir'
in
os.listdir
(
os.curdir)
Out[38
]: True
In [41
]: os.rmdir
(
'foodir'
)
In [42
]: 'foodir'
in
os.listdir
(
os.curdir)
Out[42
]: False
Supprimer un fichier :
In [44
]: fp =
open(
'junk.txt'
, 'w'
)
In [45
]: fp.close
(
)
In [46
]: 'junk.txt'
in
os.listdir
(
os.curdir)
Out[46
]: True
In [47
]: os.remove
(
'junk.txt'
)
In [48
]: 'junk.txt'
in
os.listdir
(
os.curdir)
Out[48
]: False
Manipulation de chemins d'accès :
os.path fournit les outils de manipulation de chemins d'accès :
In [70
]: fp =
open(
'junk.txt'
, 'w'
)
In [71
]: fp.close
(
)
In [72
]: a =
os.path.abspath
(
'junk.txt'
)
In [73
]: a
Out[73
]: '/Users/cburns/src/scipy2009/scipy_2009_tutorial/source/junk.txt'
In [74
]: os.path.split
(
a)
Out[74
]: (
'/Users/cburns/src/scipy2009/scipy_2009_tutorial/source'
,
'junk.txt'
)
In [78
]: os.path.dirname
(
a)
Out[78
]: '/Users/cburns/src/scipy2009/scipy_2009_tutorial/source'
In [79
]: os.path.basename
(
a)
Out[79
]: 'junk.txt'
In [80
]: os.path.splitext
(
os.path.basename
(
a))
Out[80
]: (
'junk'
, '.txt'
)
In [84
]: os.path.exists
(
'junk.txt'
)
Out[84
]: True
In [86
]: os.path.isfile
(
'junk.txt'
)
Out[86
]: True
In [87
]: os.path.isdir
(
'junk.txt'
)
Out[87
]: False
In [88
]: os.path.expanduser
(
'~/local'
)
Out[88
]: '/Users/cburns/local'
In [92
]: os.path.join
(
os.path.expanduser
(
'~'
), 'local'
, 'bin'
)
Out[92
]: '/Users/cburns/local/bin'
Lancer des commandes externes :
In [8
]: os.system
(
'ls'
)
basic_types.rst demo.py functions.rst python_language.rst standard_library.rst
control_flow.rst exceptions.rst io.rst python-
logo.png
demo2.py first_steps.rst oop.rst reusing_code.rst
Alternative à os.system
Le module sh est une alternative viable à os.system. Il fournit beaucoup de moyens permettant d'obtenir plus aisément les sorties, flux d'erreurs et codes de sortie issus des commandes externes.
In [20
]: import
sh
In [20
]: com =
sh.ls
(
)
In [21
]: print
com
basic_types.rst exceptions.rst oop.rst standard_library.rst
control_flow.rst first_steps.rst python_language.rst
demo2.py functions.rst python-
logo.png
demo.py io.rst reusing_code.rst
In [22
]: print
com.exit_code
0
In [23
]: type(
com)
Out[23
]: sh.RunningCommand
VII-A-2. Analyser un dossier▲
os.path.walk permet d'obtenir la liste des fichiers contenus dans la structure d'un dossier donné.
In [10
]: for
dirpath, dirnames, filenames in
os.walk
(
os.curdir):
....: for
fp in
filenames:
....: print
os.path.abspath
(
fp)
....:
....:
/
Users/
cburns/
src/
scipy2009/
scipy_2009_tutorial/
source/
.index.rst.swo
/
Users/
cburns/
src/
scipy2009/
scipy_2009_tutorial/
source/
.view_array.py.swp
/
Users/
cburns/
src/
scipy2009/
scipy_2009_tutorial/
source/
basic_types.rst
/
Users/
cburns/
src/
scipy2009/
scipy_2009_tutorial/
source/
conf.py
/
Users/
cburns/
src/
scipy2009/
scipy_2009_tutorial/
source/
control_flow.rst
...
Variables d'environnements :
In [9
]: import
os
In [11
]: os.environ.keys
(
)
Out[11
]:
['_'
,
'FSLDIR'
,
'TERM_PROGRAM_VERSION'
,
'FSLREMOTECALL'
,
'USER'
,
'HOME'
,
'PATH'
,
'PS1'
,
'SHELL'
,
'EDITOR'
,
'WORKON_HOME'
,
'PYTHONPATH'
,
...
In [12
]: os.environ['PYTHONPATH'
]
Out[12
]: '.:/Users/cburns/src/utils:/Users/cburns/src/nitools:
/Users/cburns/local/lib/python2.5/site-packages/:
/usr/local/lib/python2.5/site-packages/:
/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5'
In [16
]: os.getenv
(
'PYTHONPATH'
)
Out[16
]: '.:/Users/cburns/src/utils:/Users/cburns/src/nitools:
/Users/cburns/local/lib/python2.5/site-packages/:
/usr/local/lib/python2.5/site-packages/:
/Library/Frameworks/Python.framework/Versions/2.5/lib/python2.5'
VII-B. Module shutil : Opérations fichiers de haut niveau▲
shutil fournit des méthodes fort pratiques :
- shutil.rmtree : suppression de la structure complète d'un dossier, avec récursivité ;
- shutil.move : déplace un fichier ou un dossier à un autre emplacement, avec récursivité ;
- shutil.copy : permet de copier des fichiers ou des dossiers.
VII-C. Module glob : Recherche de pattern sur les fichiers▲
Le module glob fournit des outils de recherche de fichier, à base de pattern.
Par exemple, trouver tous les fichiers se finissant par .txt :
In [18
]: import
glob
In [19
]: glob.glob
(
'*.txt'
)
Out[19
]: ['holy_grail.txt'
, 'junk.txt'
, 'newfile.txt'
]
VII-D. Module sys : Informations spécifiques du système▲
Informations spécifiques au système liées à l'interpréteur Python.
- Quelle version de Python êtes-vous en train d'utiliser et où est-il installé ?
In [117
]: sys.platform
Out[117
]: 'darwin'
In [118
]: sys.version
Out[118
]: '2.5.2 (r252:60911, Feb 22 2008, 07:57:53)
\n
[GCC 4.0.1 (Apple Computer, Inc. build 5363)]'
In [119
]: sys.prefix
Out[119
]: '/Library/Frameworks/Python.framework/Versions/2.5'
- La liste des arguments passés à Python en ligne de commande :
In [100
]: sys.argv
Out[100
]: ['/Users/cburns/local/bin/ipython'
]
sys.path est une liste de strings qui indique les chemins utilisés afin de trouver des modules Python. Cette liste est initialisée depuis la variable PYTHONPATH.
In [121
]: sys.path
Out[121
]:
[''
,
'/Users/cburns/local/bin'
,
'/Users/cburns/local/lib/python2.5/site-packages/grin-1.1-py2.5.egg'
,
'/Users/cburns/local/lib/python2.5/site-packages/argparse-0.8.0-py2.5.egg'
,
'/Users/cburns/local/lib/python2.5/site-packages/urwid-0.9.7.1-py2.5.egg'
,
'/Users/cburns/local/lib/python2.5/site-packages/yolk-0.4.1-py2.5.egg'
,
'/Users/cburns/local/lib/python2.5/site-packages/virtualenv-1.2-py2.5.egg'
,
...
VII-E. Module pickle : persistance facile▲
Très pratique pour stocker arbitrairement des objets dans un fichier. Cependant, ce n'est pas le plus recommandé, ni le plus sûr.
VII-F. Exercice▲
Écrivez un programme pour rechercher votre PYTHONPATH pour le module site.py.
VIII. Les exceptions avec Python▲
Il est fort improbable que vous n'ayez jamais levé la moindre exception si vous avez saisi la totalité des commandes précédentes de ce tutoriel. Par exemple, vous avez dû en lever une si vous avez saisi une commande avec une faute de frappe.
Les exceptions sont levées pour différentes raisons, lesquelles surviennent à l'exécution du code Python. Dans votre propre code, vous vous devez d'intercepter les erreurs, ou de définir un traitement personnalisé.
Vous pouvez regarder les descriptions des exceptions déjà existantes quand vous en recherchez une.
VIII-A. Les exceptions▲
En Python, les exceptions sont levées par des erreurs :
In [1
]: 1
/
0
---------------------------------------------------------------------------
ZeroDivisionError
: integer division or
modulo by zero
In [2
]: 1
+
'e'
---------------------------------------------------------------------------
TypeError
: unsupported operand type(
s) for
+
: 'int'
and
'str'
In [3
]: d =
{1
:1
, 2
:2
}
In [4
]: d[3
]
---------------------------------------------------------------------------
KeyError
: 3
In [5
]: l =
[1
, 2
, 3
]
In [6
]: l[4
]
---------------------------------------------------------------------------
IndexError
: list index out of range
In [7
]: l.foobar
---------------------------------------------------------------------------
AttributeError
: 'list'
object has no attribute 'foobar'
Comme vous pouvez le constater, il y a différents types d'exceptions pour différents types d'erreurs.
VIII-B. Intercepter les exceptions▲
VIII-B-1. Try/except▲
In [10
]: while
True
:
....: try
:
....: x =
int(
raw_input(
'Please enter a number: '
))
....: break
....: except
ValueError
:
....: print
(
'That was no valid number. Try again...'
)
....:
Please enter a number: a
That was no valid number. Try again...
Please enter a number: 1
In [9
]: x
Out[9
]: 1
VIII-B-2. Try/finally▲
In [10
]: try
:
....: x =
int(
raw_input(
'Please enter a number: '
))
....: finally
:
....: print
(
'Thank you for your input'
)
....:
....:
Please enter a number: a
Thank you for
your input
---------------------------------------------------------------------------
ValueError
: invalid literal for
int(
) with
base 10
: 'a'
Important pour la gestion des ressources (par exemple, fermer un fichier).
VIII-B-3. Réduire au silence une exception▲
VIII-B-4. Lever des exceptions▲
Intercepter et propager une exception :
In [15
]: def
filter_name
(
name):
....: try
:
....: name =
name.encode
(
'ascii'
)
....: except
UnicodeError
, e:
....: if
name ==
'Gaël'
:
....: print
(
'OK, Gaël'
)
....: else
:
....: raise
e
....: return
name
....:
In [16
]: filter_name
(
'Gaël'
)
OK, Gaël
Out[16
]: 'Ga
\xc3\xab
l'
In [17
]: filter_name
(
'Stéfan'
)
---------------------------------------------------------------------------
UnicodeDecodeError: 'ascii'
codec can't decode byte 0xc3 in position 2: ordinal not in range(128)
Comment propager des exceptions entre différentes sections de code ?
In [17
]: def
achilles_arrow
(
x):
....: if
abs(
x -
1
) <
1e-3
:
....: raise
StopIteration
....: x =
1
-
(
1
-
x)/
2.
....: return
x
....:
In [18
]: x =
0
In [19
]: while
True
:
....: try
:
....: x =
achilles_arrow
(
x)
....: except
StopIteration
:
....: break
....:
....:
In [20
]: x
Out[20
]: 0.9990234375
Utilisez les exceptions pour notifier si certaines conditions sont remplies au cours de l'exécution du code (par exemple StopIteration) ou non (par exemple : custom error raising).
IX. Programmation orientée objet (POO)▲
Python supporte la programmation orientée objet (POO). Les buts principaux de la POO sont :
- organiser le code ;
- optimiser la ré-utilisabilité de code dans des contextes similaires.
Voici un petit exemple : nous avons créé une classe Student, laquelle est un objet contenant de multiples fonctions (ses méthodes) et de multiples variables (ses attributs), que nous pourrons utiliser :
>>>
class
Student
(
object):
... def
__init__
(
self, name):
... self.name =
name
... def
set_age
(
self, age):
... self.age =
age
... def
set_major
(
self, major):
... self.major =
major
...
>>>
anna =
Student
(
'anna'
)
>>>
anna.set_age
(
21
)
>>>
anna.set_major
(
'physics'
)
Dans l'exemple précédent, la classe Student possède des méthodes __init__, set_age, et set_major. Ses attributs sont name, age, et major. Nous pouvons appeler ces méthodes et ces attributs avec la notation suivante : classinstance.methode ou bien encore classinstance.attribute. Le constructeur __init__ est une méthode spéciale que nous appelons avec : MyClass(paramètres d'initialisation si besoin).
Maintenant, supposons que nous désirions créer une nouvelle classe MasterStudent avec les mêmes méthodes et attributs que la précédente, mais avec un attribut complémentaire internship. Nous n'allons pas copier la classe précédente, mais en hériter :
>>>
class
MasterStudent
(
Student):
... internship =
'mandatory, from March to June'
...
>>>
james =
MasterStudent
(
'james'
)
>>>
james.internship
'mandatory, from March to June'
>>>
james.set_age
(
23
)
>>>
james.age
23
La classe MasterStudent hérite des attributs et des méthodes de la classe Student.
Grâce aux classes et à la programmation orientée objet, nous pouvons organiser notre code en différentes classes correspondant chacune aux divers objets dont nous pourrions avoir besoin (une classe Experience, une classe Image, une classe Flux…), chacune possédant ses propres méthodes et ses propres attributs. Puis nous pourrons utiliser l'héritage afin de créer des variations de ces classes en réutilisant ainsi leur code. Par exemple, depuis une classe Flux, nous pouvons créer des classes FluxDAlimentation, FluxDeTurbulence, FluxPotientiels…
X. Remerciements▲
Merci aux personnes suivantes pour leur aide pour cette traduction :