9h15 - 10h45
Présentation de l'écosystème Python : environnement de développement, notion de module.
Introduction au language Python :
Après cette introduction à Python "généraliste", la séance qui suit (S2) abordera Python "numérique", c'est à dire les modules spécialisés pour le calcul scientifique et la visualisation.
Python la calculette :
1+3
4
Les objets se définissent dynamiquement :
a = 3 # entier 'int'
a = 3.3 # flottant 'float'
2 * a
6.6
Attention à la division avec les nombres entiers
print(1/2) # division euclidienne
print(1./2)
print(float(1)/2)
0 0.5 0.5
Attention, l'exposant (puissance) ne s'écrit pas avec '^' :
5**2
25
Remarque : bien que le type d'une variable ne soit jamais indiqué explicitement, chaque variable est bien typée.
Le type est récupérable avec la fonction type
:
a = 1.2e3 # notation scientifique 1,2 * 10³
type(a)
float
Nombre complexes :
à vous de chercher sur Internet ! (la meilleure façon d'accéder à l'information)
b = 1 + 1j # 1 + i
b**8
(16+0j)
Les listes en Python se notent avec des crochets [ ]. Ces mêmes crochets servent à accéder à un élément de la collection :
l = [10, 20, 30, 40, 50]
l
[10, 20, 30, 40, 50]
Pour accéder à un élément ("indexing") on utilise aussi les crochets :
l[0] # les indices commencent à 0 (comme en C, javascript) et non à 1
10
On peut indexer à partir de la fin :
l[-1] # le dernier élément
50
On peut aussi obtenir des morceaux ("slices") de liste:
l[1:3] # syntaxe [start:stop]
[20, 30]
l[0:5:2] # syntaxe [start:stop:step]
# identique à l[::2]
[10, 30, 50]
Question : utiliser la syntax start:stop:step pour obtenir la liste renversée
# Une solution :
l[::-1]
[50, 40, 30, 20, 10]
Les listes sont des objets modifiables ("mutables")
l[0] = 9
l
[9, 20, 30, 40, 50]
l.append(60) # append est une *méthode* de la list
l
[9, 20, 30, 40, 50, 60]
Aparté sur les méthodes et comment les découvrir : taper l. puis TAB dans IPython
# Les listes peuvent contenir des objets de types différents:
l2 = ['a', 'b', 'c', 4, 5, 6]
Question : comment obtenir la longeur d'une liste ?
# Solution : fonction `len`
len(l)
6
Notons enfin le comportement spécifique des opérateurs + et ***** pour les listes :
[1,2,3] + [4] # concaténation
[1, 2, 3, 4]
[1]*10
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]
nom = 'Fillon' # chaine 'str'
prenom = u'François' # chaine 'unicode', pour caractères "compliqués"
Question : qu'est-ce que l'addition (+) de 2 chaînes ?
print(prenom + ' ' + nom)
François Fillon
Remarque importante : le mélange des chaînes unicode
et str
est une très mauvaise pratique.
Python version 3 résout ce problème : toutes les chaînes sont Unicode.
Pour une bonne compréhension des concepts tels qu'Unicode et les encodages de caractèrs, je recommande la vidéo Pragmatic Unicode, or How Do I Stop the Pain ?. On y trouve aussi des "bonnes pratiques" pour résoudre et prévenir les problèmes.
Les tuples : ils ressemblent beaucoup aux listes...
a = (1,2,3)
a[0]
1
Mais grande différence, ils sont "immutables" (essayer a. + Tab
)
a[0] = 2
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-24-48f8c1dbf98d> in <module>() ----> 1 a[0] = 2 TypeError: 'tuple' object does not support item assignment
On passe facilement d'un tuple à une liste grâce à la fonction constructeur list
(et vice versa avec tuple
)
a_list = list(a) # créé une *copie* du tuple
a_list
[1, 2, 3]
Les dictionnaires sont un mapping clé -> valeur
annuaire = {u'François' : u'Élysée',
'Jean-Marc' : 'Matignon',
'Arnaud' : 'Bercy'}
# Indexation
annuaire['Jean-Marc']
# on peut également réassigner une nouvelle valeur...
'Matignon'
# Ajout dynamique :
annuaire['Manuel'] = 'Place Beauvau'
annuaire
{'Arnaud': 'Bercy', u'Fran\xe7ois': u'\xc9lys\xe9e', 'Jean-Marc': 'Matignon', 'Manuel': 'Place Beauvau'}
Autre conteneur : les ensembles set
contiennent des valeurs uniques, non ordonnées. Ils permettent les opérations d'union, d'intersection.
mes_films = {'Die Hard 25', 'Iron Man 7', 'Terminator 12'}
tes_films = {'Alien 10', 'Terminator 12', 'Iron Man 7'}
mes_films.union(tes_films)
set(['Iron Man 7', 'Alien 10', 'Terminator 12', 'Die Hard 25'])
Les conditions se font avec if
et else
(et éventuellement elif
)
stock_choco = 3
#stock_choco = 0
if stock_choco > 0:
print(u'Insérez une pièce puis servez vous...')
else:
print(u'Désolé, plus de chocolat !')
Insérez une pièce puis servez vous...
Note importante : en Python il n'y a pas de mot-clef "end". C'est simplement l'indentation qui marque la séparation des blocs logiques.
# Autres tests logiques :
stock_choco == 0 # "est égal à"
stock_choco != 0 # "est différent de"
stock_choco >= 0
True
Les boucles s'expriment avec for
# itération "classique" sur des entiers
for i in range(3):
print(i)
0 1 2
notons au passage range
est une fonction renvoyant une liste
# itération sur les élément d'une liste
tensions = [1.8, 3.3, 5, 230] # (volts)
for t in tensions:
print(t)
1.8 3.3 5 230
(En plus des boucles for
, il existe aussi boucles while
)
En Python les erreurs apparaissent dynamiquement (à part les erreurs de syntaxe)
Il y en a plusieurs "types"
if 2>1
print(2)
File "<ipython-input-35-45acae506f9e>", line 1 if 2>1 ^ SyntaxError: invalid syntax
1 + '2'
--------------------------------------------------------------------------- TypeError Traceback (most recent call last) <ipython-input-36-d79ad31fc60d> in <module>() ----> 1 1 + '2' TypeError: unsupported operand type(s) for +: 'int' and 'str'
# transformer une chaine de caractère en nombre flottant:
float('1.2') # ça marche
float('1/2') # ça non !
float('1,2') # ça non plus (voir plus bas pour une solution)
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-37-4db6f6c4de49> in <module>() 1 # transformer une chaine de caractère en nombre flottant: 2 float('1.2') # ça marche ----> 3 float('1/2') # ça non ! 4 float('1,2') # ça non plus (voir plus bas pour une solution) ValueError: invalid literal for float(): 1/2
1/0
--------------------------------------------------------------------------- ZeroDivisionError Traceback (most recent call last) <ipython-input-38-05c9758a9c21> in <module>() ----> 1 1/0 ZeroDivisionError: integer division or modulo by zero
aller plus loin avec les erreurs
try
et except
Gérer les erreurs:
try:
0/0
except ZeroDivisionError:
print('Houston, on a eu un probleme.')
%pdb
Automatic pdb calling has been turned OFF
passage de la console IPython à l'environnement de développement (IDE) Spyder
Instructions pour installer un écosystème Python incluant Spyder : http://python-prepa.github.io/intro.html
Une tâche routinière d'un code peut être empaquetée dans une fonction.
Exemple de cahier des charges de fonction :
Comment ajouter un titre de Docteur au nom d'une personne ? (concaténation de chaînes de caractères)
Bonne pratique : avant d'écrire une fonction dans un fichier, faire des essais avec des commandes interactives
nom = 'Georges'
'Dr. ' + nom
'Dr. Georges'
En Python, la définition d'une fonction se fait avec le mot-clef def,
def diplomation(nom):
nom_dipl = 'Dr. ' + nom
return nom_dipl
diplomation('Georges Dumont')
'Dr. Georges Dumont'
On peut (ou on doit ?!?) documenter une fonction grâce à une Docstring
def diplomation(nom):
'''cette fonction ajoute un titre de docteur au nom d'une personne
'''
return 'Dr. ' + nom
diplomation('Georges Dumont')
'Dr. Georges Dumont'
# voir la documentation
diplomation?
Remaque : si une fonction de contient pas de return
, elle ne renvoie pas rien mais l'objet None
def saluer():
print('Bonjour Docteur !')
a = saluer()
print(a)
Bonjour Docteur ! None
On peut mettre plusieurs arguments (ou bien zéro) et ces arguments peuvent être optionnels si on leur attribut une valeur par défaut
def diplomation(nom, nb=1, titre='Dr.'):
'''cette fonction ajoute un titre de docteur au nom d'une personne
le nombre de doctorat est réglable (1) par défaut
'''
return (titre+' ')*nb + nom
print(diplomation('Georges Dumont'))
print(diplomation('Georges Dumont', 2))
Dr. Georges Dumont Dr. Dr. Georges Dumont
Les arguments peuvent être assignés par leur nom :
print(diplomation('Georges Dumont', nb=2))
print(diplomation('Georges Dumont', titre='Dr. Prof.'))
Dr. Dr. Georges Dumont Dr. Prof. Georges Dumont
En bonus, une fonction qui peut lever (mot-clé raise
) une erreur ValueError
(et Python pointe l'endroit exacte de l'erreur, avec tout la pile d'appel des fonctions "stack trace")
def diplomation(nom, nb=1, titre='Dr.'):
'''cette fonction ajoute un titre de docteur au nom d'une personne
le nombre de doctorat est réglable (1) par défaut
'''
if nb > 3:
raise ValueError("Impossible d'avoir plus de 3 doctorats !")
return (titre+' ')*nb + nom
print(diplomation('Georges Dumont', nb=2))
print(diplomation('Georges Dumont', nb=4))
--------------------------------------------------------------------------- ValueError Traceback (most recent call last) <ipython-input-46-bb5be41408f7> in <module>() 8 9 print(diplomation('Georges Dumont', nb=2)) ---> 10 print(diplomation('Georges Dumont', nb=4)) <ipython-input-46-bb5be41408f7> in diplomation(nom, nb, titre) 4 ''' 5 if nb > 3: ----> 6 raise ValueError("Impossible d'avoir plus de 3 doctorats !") 7 return (titre+' ')*nb + nom 8 ValueError: Impossible d'avoir plus de 3 doctorats !
Dr. Dr. Georges Dumont
La plupart des fonctions disponibles en Python sont empaqueté dans des modules.
Ces modules permettent par exemple de :
Un certain nombre fait partie de la bibliothèque standard, beaucoup d'autres sont à installer séparément.
Pour pouvoir les utiliser (une fois installé), il faut les "importer"
import math # un module "standard"
Une fois importé, on peut accéder à leur contenu : classes, fonctions et parfois variables :
pi = math.pi
print(pi)
3.14159265359
print(math.cos(pi/3))
print(math.sin(pi/3))
print(math.sqrt(3)/2)
0.5 0.866025403784 0.866025403784
# Remaquons au passage l'inexactitude inévitable des nombres flottants :
print(math.cos(pi/3) == 0.5) # cette comparaison "semble vraie"
math.cos(pi/3)
False
0.5000000000000001
Question importante : Comment savoir ce que contient le module math
? Comment même savoir qu'il existe ?
Réflexe 1 : taper math. + Tab dans IPython
Réflexe 2 : documentation officielle http://docs.python.org
Aller plus loin : créer ses propres modules (Python tutorial http://docs.python.org/2/tutorial/modules.html)
(empaqueter ses fonctions dans un module que l'on peut réutiliser fait partie des "bonnes pratiques")
Contenu :
Pour lire le contenu d'un fichier, il faut l'ouvrir avec la fonction open
(pas besoin de module)
fname = 'S1_Bases_Python/bode_data_FR.csv'
f = open(fname)
# On obtien un objet "file" ouvert (~ un "pointeur")
f
<open file 'S1_Bases_Python/bode_data_FR.csv', mode 'r' at 0x3ed64b0>
# afficher les 3 premières lignes
for i in range(3):
print(f.readline()) ,
#f.close()
# Ficher CSV formaté "à la française" 1,000000e+02;6,155659e+00;-2,409978e+00 1,047616e+02;6,001112e+00;-2,346197e+00
# On ferme le fichier une fois le travail fini:
f.close()
f
# À essayer: lire le fichier après qu'il soit fermé
#f.readline()
<closed file 'S1_Bases_Python/bode_data_FR.csv', mode 'r' at 0x3d15ed0>
Ce fichier CSV est formaté "à la française". Peu d'outils interprèterons la "," comme marque décimale.
On va donc le convertir avec un script de "rechercher-remplacer" ligne par ligne.
Pour cela, on utilise la méthode replace
des chaînes de caractère
ligne = f.readline()
print(ligne)
ligne = ligne.replace(',', '.')
print(ligne)
ligne = ligne.replace(';', ',')
print(ligne)
1,097499e+02;5,810821e+00;-2,225484e+00 1.097499e+02;5.810821e+00;-2.225484e+00 1.097499e+02,5.810821e+00,-2.225484e+00
Les chaînes de caractères sont des types de listes spécialisées pour contenir du texte.
a = 'La SI c\'est sympa' # notez le caractère d'échapement "\"
# ou bien
a = "La SI c'est sympa" # (identique au précédent)
On remarque que les chaînes de caractères disposent de plusieurs méthodes pour le manipuler :
# Taper "TAB" pour voir la liste des méthodes:
a.
les méthodes split
, replace
, format
, ... sont particulièrement utiles.
D'autres sont d'utilisation ponctuelles.
# Couper une chaîne à l'aide d'un motif :
a.split('SI') # -> renvoie une liste de str !
['La ', " c'est sympa"]
a1, a2 = a.split('SI')
print(a1 + u"Méca" + a2) # notons le u qui préfixe u"Méca" !
La Méca c'est sympa
Le formattage de chaînes, en accéléré (se référer à http://docs.python.org/2/library/string.html#format-string-syntax pour aller plus loin)
Le but : fabriquer une chaine de caractères qui intègre la valeur d'une variable
# Formattage avec des chaînes
prenom = u'Geneviève'
nom = u'Fioraso'
print(u"Bonjour Mme {} {}".format(prenom, nom))
# Remarque : cce même résultat peut être obtenu par concaténation:
print(u'Bonjour Mme ' + prenom + u' ' + nom)
Bonjour Mme Geneviève Fioraso Bonjour Mme Geneviève Fioraso
# Formattage avec des nombres:
n = 5
t = 2.1862
u"l'algo a convergé en {} itérations".format(n)
u"la simulation a duré {:.2f} secondes".format(t)
u'la simulation a dur\xe9 2.19 secondes'
# Exemple de méthodes d'utilisation ponctuelles (de mon point de vue...)
# Mettre en minuscule
a.lower()
# Mettre en majuscule
a.upper()
"LA SI C'EST SYMPA"
Pour transcrire tout le fichier, on ouvre
L'écriture se fait avec la méthode write
de l'objet fichier.
fname_in = 'S1_Bases_Python/bode_data_FR.csv'
f_in = open(fname)
fname_out = 'S1_Bases_Python/bode_data_EN.csv'
# ou bien:
#fname_out = fname_in.split('.')[0] + '_to_EN.csv'
print('transcription dans le fichier "'+ fname_out + '"')
f_out = open(fname_out, 'w') # Notez le "w"
# Itération sur les lignes:
for ligne in f_in:
ligne = ligne.replace(',', '.')
ligne = ligne.replace(';', ',')
f_out.write(ligne)
# fermeture des fichiers:
f_in.close()
f_out.close()
transcription dans le fichier "S1_Bases_Python/bode_data_EN.csv"
# vérification du résultat:
f = open(fname_out)
for i in range(3):
print(f.readline()) ,
# Ficher CSV formaté "à la française" 1.000000e+02,6.155659e+00,-2.409978e+00 1.047616e+02,6.001112e+00,-2.346197e+00
Aller plus loin avec les fichiers et les chaînes de caractères :
La méthode recommandée d'ouvrir un fichier avec le mot-clef with
with open('monfichier.txt') as f: f.readline()
Pour traiter des chaînes de caractères plus compliquées, il y a un module d'expressions rationnelles ("regexp") : re
import re
-> se reporter à sa documentation officielle sur http://docs.python.org/2/library/re.html
fin de la session 1
Ce support de formation créé par Pierre Haessig est mis à disposition selon les termes de la licence Creative Commons Attribution 3.0 France.