Séance 1 : Introduction au langage Python

Formation Python du département Mécatronique

9h15 - 10h45

Présentation de l'écosystème Python : environnement de développement, notion de module.

Introduction au language Python :

  1. Arithmétique. Instructions et types de données de bases. Boucles et conditions
  2. Manipulation de listes, de chaînes de caractères
  3. Manipulation de fichiers (lecture, écriture)

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.

A) Instructions et types de base

A1) Un peu d'arithmétique

Python la calculette :

In [1]:
1+3
Out[1]:
4

Les objets se définissent dynamiquement :

In [2]:
a = 3 # entier 'int'
a = 3.3 # flottant 'float' 
2 * a
Out[2]:
6.6

Attention à la division avec les nombres entiers

In [3]:
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 '^' :

In [4]:
5**2
Out[4]:
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 :

In [6]:
a = 1.2e3 # notation scientifique 1,2 * 10³
type(a)
Out[6]:
float

Nombre complexes :

à vous de chercher sur Internet ! (la meilleure façon d'accéder à l'information)

In [7]:
b = ... # 1 + i
b**8
Out[7]:
(16+0j)

A2) Les listes, une collection ordonnée d'objets

Les listes en Python se notent avec des crochets [ ]. Ces mêmes crochets servent à accéder à un élément de la collection :

In [8]:
l = [10, 20, 30, 40, 50]
l
Out[8]:
[10, 20, 30, 40, 50]

Pour accéder à un élément ("indexing") on utilise aussi les crochets :

In [9]:
l[0] # les indices commencent à 0 (comme en C, javascript) et non à 1
Out[9]:
10

On peut indexer à partir de la fin :

In [10]:
l[-1] # le dernier élément
Out[10]:
50

On peut aussi obtenir des morceaux ("slices") de liste:

In [11]:
l[1:3] # syntaxe [start:stop]
Out[11]:
[20, 30]
In [12]:
l[0:5:2] # syntaxe [start:stop:step]
# identique à l[::2]
Out[12]:
[10, 30, 50]

Question : utiliser la syntax start:stop:step pour obtenir la liste renversée

In [13]:
...
Out[13]:
[50, 40, 30, 20, 10]

Les listes sont des objets modifiables ("mutables")

In [14]:
l[0] = 9
l
Out[14]:
[9, 20, 30, 40, 50]
In [15]:
l.append(60) # append est une *méthode* de la list
l
Out[15]:
[9, 20, 30, 40, 50, 60]

Aparté sur les méthodes et comment les découvrir : taper l. puis TAB dans IPython

In [16]:
# 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 ?

In [17]:
...
Out[17]:
6

Notons enfin le comportement spécifique des opérateurs + et * pour les listes :

In [18]:
[1,2,3] + [4] # concaténation
Out[18]:
[1, 2, 3, 4]
In [19]:
[1]*10
Out[19]:
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1]

A3) Chaînes de caractères (str)

In [21]:
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 ?

In [22]:
...
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.

A4) Autres conteneurs : tuple, dict, set

Les tuples : ils ressemblent beaucoup aux listes...

In [23]:
a = (1,2,3)
a[0]
Out[23]:
1

Mais grande différence, ils sont "immutables" (essayer a. + Tab)

In [24]:
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)

In [25]:
a_list = list(a) # créé une *copie* du tuple
a_list
Out[25]:
[1, 2, 3]

Les dictionnaires sont un mapping clé -> valeur

In [26]:
annuaire = {u'François' : u'Élysée',
            'Jean-Marc' : 'Matignon',
            'Arnaud' : 'Bercy'}
In [27]:
# Indexation
annuaire['Jean-Marc']
# on peut également réassigner une nouvelle valeur...
Out[27]:
'Matignon'
In [28]:
# Ajout dynamique :
annuaire['Manuel'] = 'Place Beauvau'
annuaire
Out[28]:
{'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.

In [29]:
mes_films = {'Die Hard 25', 'Iron Man 7', 'Terminator 12'}
In [30]:
tes_films = {'Alien 10', 'Terminator 12', 'Iron Man 7'}
mes_films.union(tes_films)
Out[30]:
set(['Iron Man 7', 'Alien 10', 'Terminator 12', 'Die Hard 25'])

A5) Boucles et conditions

Les conditions se font avec if et else (et éventuellement elif )

In [31]:
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.

In [32]:
# Autres tests logiques :
stock_choco == 0 # "est égal à"
stock_choco != 0 # "est différent de"
stock_choco >= 0
Out[32]:
True

Les boucles s'expriment avec for

In [33]:
# 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

In [34]:
# 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)

A6) Les erreurs

En Python les erreurs apparaissent dynamiquement (à part les erreurs de syntaxe)

Il y en a plusieurs "types"

In [35]:
if 2>1
    print(2)
  File "<ipython-input-35-45acae506f9e>", line 1
    if 2>1
          ^
SyntaxError: invalid syntax
In [36]:
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'
In [37]:
# 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
In [38]:
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

  • utiliser le débuggeur Python (le plus simple me semble être mode "débuggage automatique" d'Ipython, activé avec %pdb )
  • les "attraper" avec try et except

Gérer les erreurs:

try:
    0/0
except ZeroDivisionError:
    print('Houston, on a eu un probleme.')
In [85]:
%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

B) Fonctions, modules

B1) Créer, utiliser des fonctions

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

In [39]:
nom = 'Georges'
'Dr. ' + nom
Out[39]:
'Dr. Georges'

En Python, la définition d'une fonction se fait avec le mot-clef def,

  • suivi du nom de la fonction,
  • suivi des arguments entre parenthèses
In [40]:
def diplomation(nom):
    nom_dipl = 'Dr. ' + nom
    return nom_dipl

diplomation('Georges Dumont')
Out[40]:
'Dr. Georges Dumont'

On peut (ou on doit ?!?) documenter une fonction grâce à une Docstring

In [41]:
def diplomation(nom):
    '''cette fonction ajoute un titre de docteur au nom d'une personne
    '''
    return 'Dr. ' + nom

diplomation('Georges Dumont')
Out[41]:
'Dr. Georges Dumont'
In [42]:
# voir la documentation
diplomation?

Remaque : si une fonction de contient pas de return, elle ne renvoie pas rien mais l'objet None

In [43]:
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

In [44]:
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 :

In [45]:
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")

In [46]:
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

B2) Les "modules" pour des fonctionnalités supplémentaires

La plupart des fonctions disponibles en Python sont empaqueté dans des modules.

Ces modules permettent par exemple de :

  • télécharger des fichiers sur Internet,
  • manipuler des bases de données,
  • faire des interface graphiques, ...

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"

In [48]:
import math # un module "standard"

Une fois importé, on peut accéder à leur contenu : classes, fonctions et parfois variables :

In [49]:
pi = math.pi
print(pi)
3.14159265359
In [50]:
print(math.cos(pi/3))
print(math.sin(pi/3))
print(math.sqrt(3)/2)
0.5
0.866025403784
0.866025403784
In [51]:
# 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
Out[51]:
0.5000000000000001

Question importante : Comment savoir ce que contient le module math ? Comment même savoir qu'il existe ?

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")


C) Fichiers et chaînes de caractères : petite application

Contenu :

  • lecture et écriture de fichier,
  • manipulation simple de chaînes de caractèrs,
  • dans le but de transcrire un ficher CSV du format "français" au format usuel.

C1) Ouvrir et lire un fichier

Pour lire le contenu d'un fichier, il faut l'ouvrir avec la fonction open (pas besoin de module)

In [59]:
fname = 'S1_Bases_Python/bode_data_FR.csv'
f = open(fname)
# On obtien un objet "file" ouvert (~ un "pointeur")
f
Out[59]:
<open file 'S1_Bases_Python/bode_data_FR.csv', mode 'r' at 0x3ed64b0>
In [60]:
# 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
In [55]:
# On ferme le fichier une fois le travail fini:
f.close()
f

# À essayer: lire le fichier après qu'il soit fermé
#f.readline()
Out[55]:
<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.

  • "," transformé en "."
  • ";" transformé en "," (ça c'est plus facultatif)

Pour cela, on utilise la méthode replace des chaînes de caractère

In [61]:
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

C2) Manipuler des chaînes de caractères

Les chaînes de caractères sont des types de listes spécialisées pour contenir du texte.

In [63]:
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 :

In [ ]:
# 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.

In [66]:
# Couper une chaîne à l'aide d'un motif :
a.split('SI') # -> renvoie une liste de str !
Out[66]:
['La ', " c'est sympa"]
In [67]:
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

In [68]:
# 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
In [69]:
# 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)
Out[69]:
u'la simulation a dur\xe9 2.19 secondes'
In [70]:
# Exemple de méthodes d'utilisation ponctuelles (de mon point de vue...)

# Mettre en minuscule
a.lower()
# Mettre en majuscule
a.upper()
Out[70]:
"LA SI C'EST SYMPA"

C3) Écriture dans un fichier

Pour transcrire tout le fichier, on ouvre

  • le fichier original en mode lecture : 'r' (mode par défaut)
  • le fichier transcrit en mode écriture : 'w'

L'écriture se fait avec la méthode write de l'objet fichier.

In [71]:
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"
In [72]:
# 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 :

1) La méthode recommandée d'ouvrir un fichier avec le mot-clef with

with open('monfichier.txt') as f:
    f.readline()

2) 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

Licence Creative Commons

Ce <span xmlns:dct="http://purl.org/dc/terms/" href="http://purl.org/dc/dcmitype/InteractiveResource" rel="dct:type">support de formation</span> créé par <span xmlns:cc="http://creativecommons.org/ns#" property="cc:attributionName">Pierre Haessig</span> est mis à disposition selon les termes de la licence Creative Commons Attribution 3.0 France.