Introduction à Python

Nicolas Dumoulin nicolas.dumoulin@irstea.fr

7 Juin 2017

Préambule

Ce document est librement réutilisable selon les termes de la licence GNU FDL version 1.2 et supérieures.

Vous pouvez charger ce document interactif en version notebook (extension .ipynb), en démarrant ipython notebook (version 2.7) depuis le répertoire contenant ce document, ou bien en faisant glisser le document sur la page web du notebook après l'avoir démarré. Voir aussi la documentation de notebook.

Qu'est-ce que Python ?

  • Un langage
  • Une suite d'outils sous licence libre
  • Une bibliothèque en standard bien fournie
  • Une plate-forme pour faire :
    • Des applications sur poste client (Qt)
    • Des applications pour le web (Django)
    • Des surcouches à des codes de calculs (C, C++, Fortran, …)
    • Du bidouillage interactif

Ressources en lignes :

Comment démarrer

Deux modes d'utilisation :

  • Mode interactif (console)
  • Exécution de script

Premier contact, démarrer la console interactive : python (version 2.x selon les systèmes) Pour quitter la console : [Ctrl] + [D]

ipython est un interpréteur plus évolué qui propose de nombreuses extensions.

On peut taper une opération arithmétique et on obtient le résultat.

In [1]:
2 + 5 / 2
Out[1]:
4.5
In [2]:
4*2
Out[2]:
8

Vous pouvez taper les mêmes commandes dans un fichier texte (extension .py) et l'exécuter : python monScript.py

Variables et types de données

Le typage d'une variable est dynamique, le type est inféré lors de l'affectation.

In [3]:
i = 1
d = 0.7
s = "bonjour"
In [4]:
nb = 3 + 2j
type(nb)
Out[4]:
complex
In [5]:
type(i)
Out[5]:
int
In [6]:
type(d)
Out[6]:
float
In [7]:
type(s)
Out[7]:
str

La variable spéciale _ contient la dernière valeur affichée

In [8]:
3*2
Out[8]:
6
In [9]:
_+2
Out[9]:
8

Chaînes de caractère

In [10]:
s1 = "N'importe quoi" # avec des guillemets double, cela permet d'utiliser une apostrophe dans le texte
s2 = 'N\'importe quoi' # avec des guillemets simple, l'apostrophe doit être échappée avec l'antislash \
s3 = 'Je disais "N\'importe quoi"' # avec des guillemets simple, cela permet d'utiliser des guillemets doubles dans le texte
s4 = """Je disais "N'importe quoi" """ # avec trois guillemets doubles (ou simples), pas besoin d'échapper les guillemets et apostrophes
s5 = """Les triples guillemets permettent d'écrire
plusieurs lignes"""
print(s5)
Les triples guillemets permettent d'écrire
plusieurs lignes
In [11]:
i + d
Out[11]:
1.7

Problème avec des types non compatibles

i + s

On doit alors transtyper (caster) les variables

In [12]:
"Votre valeur est : "+str(d)
Out[12]:
'Votre valeur est : 0.7'
In [13]:
str(i) + s
Out[13]:
'1bonjour'

Variables booléenes

In [14]:
true = True
vrai = true
faux = False

Opérateurs et fonctions de base

On les trouve sous le nom de builtin functions dans la documentation anglophone.

La fonction print() permet d'afficher le contenu d'une variable, et plus généralement une chaîne de caractère.

In [15]:
print(s1)
print("Ceci est un entier : "+str(i))
N'importe quoi
Ceci est un entier : 1
In [16]:
j=4
print("i = %d, j = %d" % (i,j))
i = 1, j = 4

%d pour les entiers, %f pour les flottants et %s pour les chaînes

La fonction help() permet d'obtenir la documentation d'une fonction (python 3).

La fonction len permet de connaître la taille d'un tableau

In [17]:
len("Bonjour")
Out[17]:
7

Opérateurs et fonctions arithmétiques

Documentation : http://docs.python.org/2/library/stdtypes.html#numeric-types-int-float-long-complex

In [18]:
5/2 # division entière en python 2.x mais division flottante à partir de 3.0
Out[18]:
2.5
In [19]:
5.0/2
Out[19]:
2.5
In [20]:
5.0//2
Out[20]:
2.0
In [21]:
int(5.0//2) # conversion de float en int
Out[21]:
2
In [22]:
5%2 # reste de la division entière
Out[22]:
1

Opérateurs booléens

In [23]:
b = True
"oui" == "oui"
Out[23]:
True
In [24]:
3+1 == 4 and 5*2 == 20
Out[24]:
False
In [25]:
b == False or not 2 == 2 # utilisation du "et" logique et de la négation
Out[25]:
False
In [26]:
not b == False and 2 != 2 # la négation ne sera appliquée qu'à la première expression
Out[26]:
False
In [27]:
not (b == False and 2 != 2) # notez la différence avec les parenthèses
Out[27]:
True

Structures de contrôle

Documentation : http://docs.python.org/2/tutorial/controlflow.html

Attention à l'indentation !

In [28]:
i = 30
if i<30:
    print("petit")
elif i==30:
    print ("i vaut 30")
    if i == 30:
        print("fin")
else:
    print ("grand")
if i%5 == 0:
    print("multiple de 5")       
i vaut 30
fin
multiple de 5
In [29]:
if i==30: print("OK")
OK

La fonction range permet de créer des intervalles

In [30]:
len(range(3,10))
Out[30]:
7
In [31]:
for i in range(4):
    print(str(i) + " ici, c'est la boucle")
print("ici, c'est fini")
0 ici, c'est la boucle
1 ici, c'est la boucle
2 ici, c'est la boucle
3 ici, c'est la boucle
ici, c'est fini
In [32]:
i=0
while i<5:
    print("i monte")
    i += 1 # i = i + 1
print(i)
i monte
i monte
i monte
i monte
i monte
5

Structures de données

Les listes (tableaux)

L'indiçage des séquences commence à 0

In [33]:
t = [ 'un', 'deux', 'trois', 3.14 ]
t[0]
Out[33]:
'un'
In [34]:
m = [[1,2],[3,4]]
m
Out[34]:
[[1, 2], [3, 4]]
In [35]:
s = "Bonjour, comment allez-vous?"
s[0:7] # slicing
Out[35]:
'Bonjour'
In [36]:
s[:7] # l'indice de début est optionnel quand c'est 0
Out[36]:
'Bonjour'
In [37]:
s[9:16]
Out[37]:
'comment'
In [38]:
s[-5:]
Out[38]:
'vous?'
In [39]:
t[-1]='!' # modification du dernier élément du tableau
t
Out[39]:
['un', 'deux', 'trois', '!']

Petit exercice pour suivre les références d'objets

In [40]:
s1="un"
s2="deux"
s3 = s2
s2 = "rien"
print (s3) # s3 n'est pas modifé
deux
In [41]:
l2 = [2,4,6]
l3 = l2
l4 = l2[:] # le slicing produit un nouveau tableau et donc un nouvel objet
l2[2]=12
print(l3) # l3 subit la modification sur l2, car les deux référencent le même objet
print(l4) # l4 n'est pas affecté, car il ne référence pas le même objet que l2
[2, 4, 12]
[2, 4, 6]

Boucles sur les tableaux

In [42]:
print("vous" in s) # test d'appartenance
True

Pour faire une boucle sur les éléments du tableau :

In [43]:
for element in t:
    print(element)
un
deux
trois
!
In [44]:
for i in range(len(t)):
          print(t[i])
un
deux
trois
!

Si vous voulez aussi l'indice, la fonction zip est pour vous. zip retourne une liste d'éléments à 2 valeurs, qui sont donc affectés dans la boucle aux variables indice et element

In [45]:
zip(range(len(t)),t)
Out[45]:
<zip at 0x7f09b43c0a88>

Bon, OK c'est un objet "zip" sur lequel on pourra itérer. Si on veut "voir" son contenu, on peut le convertir en liste.

In [46]:
list(zip(range(len(t)),t))
Out[46]:
[(0, 'un'), (1, 'deux'), (2, 'trois'), (3, '!')]
In [47]:
for indice,element in zip(range(len(t)),t):
    print(str(indice) + " -> " + element)
0 -> un
1 -> deux
2 -> trois
3 -> !

Comment fonctionne l'affectation multiple

In [48]:
a,b = 1,2
print ("a = "+str(a))
print("b = "+str(b))
def mafonction():
    return ["plop","tagada"]
s1,s2 = mafonction() # le premier élément du tableau retourné va dans s1, le deuxième dans s2
print(s1)
a = 1
b = 2
plop

Les dictionnaires

Listes d'associations clé/valeur

In [49]:
d = {'Janvier':31,'Février':28,'Mars':31,'Avril':30,'Mai':31,'Juin':30,
'Juillet':31,'Août':31,'Septembre':30,'Octobre':31,'Novembre':30,u'Décembre':31}
print("d = %s" % d)
print("septembre %s" % d['Septembre'])
print("boucle :")
for cle,valeur in d.items():
    if valeur==31:
        print(cle)
d = {'Avril': 30, 'Juin': 30, 'Janvier': 31, 'Septembre': 30, 'Mai': 31, 'Novembre': 30, 'Juillet': 31, 'Octobre': 31, 'Décembre': 31, 'Mars': 31, 'Février': 28, 'Août': 31}
septembre 30
boucle :
Janvier
Mai
Juillet
Octobre
Décembre
Mars
Août
In [50]:
d2 =  { "Paul" : { "categorie" : "VM1", "mean": 3.4, "sd": 1}, "Pierre" : {"categorie":"CM1", "mean":2, "sd":0.4}}
print(d2["Paul"]["mean"])
d2
3.4
Out[50]:
{'Paul': {'categorie': 'VM1', 'mean': 3.4, 'sd': 1},
 'Pierre': {'categorie': 'CM1', 'mean': 2, 'sd': 0.4}}

Affichage disgracieux pour les caractères accentués dû à l'encodage en unicode, mieux géré avec python 3. Plus d'information sur la gestion de l'unicode avec Python 2.7.x ici.

In [51]:
d.pop('Septembre')
# print(d['Septembre']) # n'existe plus
print('Septembre' in d)
False

Un peu de programmation fonctionnelle avec les « compréhensions de listes »

In [52]:
t = [1,4,8,5,4,7,10]

Comment récupérer les nombres pairs ?

Avec une boucle classique :

In [53]:
resultat = []
for element in t:
    if element%2 == 0:
        resultat.append(element)
print(resultat)
[4, 8, 4, 10]

Avec les compréhensions de listes :

In [54]:
resultat = [element*2 for element in t if element%2 == 0]
resultat
Out[54]:
[8, 16, 8, 20]
In [55]:
[cle for cle,valeur in d.items() if valeur==30]
Out[55]:
['Avril', 'Juin', 'Novembre']

Avec la fonction filter et une fonction anonyme lambda

In [56]:
def monfiltre(element):
    return element%2 == 0
monfiltre(6)
Out[56]:
True
In [57]:
list(filter(monfiltre, t))
Out[57]:
[4, 8, 4, 10]
In [58]:
resultat = filter(lambda element:element%2 == 0, t) # prend en argument une fonction de filtre et la liste à filtrer
print(resultat)
resultat = list(resultat) # nécessaire en python 3 car filter retourne un objet itérable de type "filter"
print(resultat)
<filter object at 0x7f09b43ab7f0>
[4, 8, 4, 10]
In [59]:
resultat = map(lambda x:str(x), t) # applique une fonction à chaque élément
list(resultat)
Out[59]:
['1', '4', '8', '5', '4', '7', '10']
In [60]:
print(str(t))
eval(str(t))
[1, 4, 8, 5, 4, 7, 10]
Out[60]:
[1, 4, 8, 5, 4, 7, 10]
In [61]:
t2=t
t[0]=42
print(t)
t[0]=1
[42, 4, 8, 5, 4, 7, 10]
In [62]:
map(str, t) # simplification de l'exemple précédent, car la fonction str est adéquate au `map`
t[2]=8
t2= t[:]
t[2]=5
t2
Out[62]:
[1, 4, 8, 5, 4, 7, 10]

Écrire des fonctions

In [63]:
def salut(nom):
    print("Salut " + nom)
salut("Nicolas")
Salut Nicolas
In [64]:
def salut2(nom, majuscule):
    message = "Salut " + nom
    if majuscule:
        message = message.upper()
    print(message)
salut2("Nicolas", True)
# salut2("Nicolas") # erreur car il faut 2 arguments
SALUT NICOLAS
In [65]:
def salut3(nom, majuscule=True):
    message = "Salut " + nom
    if majuscule:
        message = message.upper()
    print(message)
salut3("Nicolas")
salut3("Nicolas", False)
salut3("Nicolas", majuscule=False) # argument nommé pour plus de clarté et lever des ambiguités
salut3(majuscule=False, nom="Nicolas")
SALUT NICOLAS
Salut Nicolas
Salut Nicolas
Salut Nicolas

Fonction avec retour de valeur en utilisant l'instruction return

In [66]:
def selection(liste, pair=True):
    """
    Fais quelquechose.
    """
    return [element for element in liste if (element%2 == 0) == pair]
print(selection([1,4,7,12]))
print(selection([1,4,7,12], pair=False))
[4, 12]
[1, 7]
In [67]:
help(selection)
Help on function selection in module __main__:

selection(liste, pair=True)
    Fais quelquechose.

Les scripts

Pour graver dans la silice vos fabuleuses lignes de code, vous pouvez les écrire dans un fichier.

Exemple avec ce fichier script.py :

a = 3
b = 4
print(a*b)

Vous pouvez déclarer plusieurs fonctions dans votre scripts et du code principal (hors fonction, qui sera exécuté) :

def salut(nom):
  print("Salut " + nom)

salut("Nicolas")

Pour exécuter ce script :

  • dans un terminal : python script.py
  • dans ipython : %run script.py
In [68]:
%run script.py
bonjour("Robert")
Bonjour Nicolas
Bonjour Robert

Les fichiers

In [69]:
f = open('script.py', 'r')
print("Lit la ligne suivante dans le fichier :")
print(f.readline())
print("Lit le reste du fichier")
print(f.read())
f.close()
Lit la ligne suivante dans le fichier :
def bonjour(nom):

Lit le reste du fichier
  print("Bonjour " + nom)

pi = "Ceci n'est pas PI"
bonjour("Nicolas")

In [70]:
sortie = open('sortie.txt', 'w')
for valeur in ['un','deux','trois']:
    sortie.write(valeur + "\n")
sortie.close()
In [71]:
%%bash
cat sortie.txt
un
deux
trois
In [72]:
with open('sortie.txt', 'r') as f:
    num = 1
    for ligne in f:
        print(str(num) + " : " + ligne)
        num += 1
1 : un

2 : deux

3 : trois

Les modules

Les bibliothèques additionnelles fournissent des fonctions et données supplémentaires en utilisant des modules pour éviter les conflits de nommage. Pour accéder à ces fonctions, vous devez au préalable importer le module correspondant.

In [73]:
import math
print(math.pi)
from math import pi
print(pi)
from math import *
print(pi)
from math import pi as thepi
print(thepi)
3.141592653589793
3.141592653589793
3.141592653589793
3.141592653589793

Ces modules peuvent être fournis par votre installation python, mais aussi par de simples scripts python.

In [74]:
import script
script.bonjour("Paul")
Bonjour Nicolas
Bonjour Paul

Si on importe un module du même nom, il écrase le précédent, d'où l'intérêt des alias si on veut utiliser les deux

In [75]:
from script import pi
print(pi)
print(thepi)
Ceci n'est pas PI
3.141592653589793

Le chargement du script a provoqué l'exécution du code hors-fonction (bonjour("Nicolas")). Nous pouvons alors modifier notre script pour que ce code d'exemple (ou par défaut) ne soit exécuté que lorsque le script est invoqué directement :

if __name__ == "__main__":
  bonjour("Nicolas")
In [76]:
import script2
from script2 import bonjour
bonjour('Nicolas')
Bonjour Nicolas
In [77]:
%%bash
cat script2.py
mavariable = "depuis le script"

def bonjour(nom):
  """Affiche un message de bienvenue
  """
  mavariable = "Bonjour "
  print(mavariable + nom)

if __name__=="__main__":
  import sys
  print(sys.argv)
  bonjour(sys.argv[1])
  print("mavariable = "+ mavariable)

Utilisation d'arguments avec %run, équivalent à exécuter le script avec la commande python script2.py Bernard.

In [78]:
%run script2.py Bernard
['script2.py', 'Bernard']
Bonjour Bernard
mavariable = depuis le script
In [79]:
help(bonjour)
Help on function bonjour in module __main__:

bonjour(nom)
    Affiche un message de bienvenue

Modules intéressants

  • sys

sys.argv contient les arguments d'un script

if __name__ == "__main__":
  import sys
  bonjour(sys.argv[1])

In [80]:
import csv
with open('donnees.csv','r') as f:
    for ligne in csv.reader(f):
        print(map(int,ligne))
<map object at 0x7f09b4345c88>
<map object at 0x7f09b4345c88>
<map object at 0x7f09b43ab9e8>
In [81]:
import csv
f= open('donnees.csv','r')
monCsvReader = csv.reader(f)
toutesMesDonnees = []
for ligne in monCsvReader:
    donnees = list(map(int,ligne))
    toutesMesDonnees.append(donnees)
f.close()
print(toutesMesDonnees)
[[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]]
In [82]:
import math
math.cos(math.pi)
Out[82]:
-1.0
In [83]:
from math import *
exp(0)
Out[83]:
1.0
  • request (Python 3) Pour s'amuser avec les données en ligne

Avec python 2.7, on peut faire l'équivalent avec les modules urllib2 et json

In [84]:
import requests
r = requests.get('http://overpass-api.de/api/interpreter?data=%5Bout%3Ajson%5D%3Bnode%5B%22short%5Fname%22%3D%22ISIMA%22%5D%3Bnode%28around%3A500%29%5B%22emergency%22%3D%22defibrillator%22%5D%3Bout%20ids%3B%0A')
data = r.json()
aeds = len(data[u'elements'])
print(str(aeds) + " défibrillateurs à moins de 500 mètres d'ici")
4 défibrillateurs à moins de 500 mètres d'ici

Aperçu des classes et exceptions

In [85]:
class Signet:
    def __init__(self, name, url):
        self.name = name
        self.url = url
    def updateURL(self, url):
        self.url = url
    def test(self):
        from urllib import request, error
        try:
            request.urlopen(self.url)
        except error.URLError:
            return False
        return True
docPython = Signet("doc python", "http://docs.python.org")
print(docPython.url)
print(docPython.test())
docPython.updateURL("http://")
print(docPython.url)
print(docPython.test())
http://docs.python.org
True
http://
False

Exemple de graphique avec pylab

In [86]:
import pandas as pd
%matplotlib inline
import matplotlib.pyplot as plt
frame=pd.read_csv('compareDistances-absolute.csv',names=("from","to","abs","rel","odo","osm","dabs","drel","dodo","dosm"))
plt.scatter(frame['abs'],frame.rel)
plt.ylabel("Erreur relative")
plt.xlabel("Erreur absolue (km)")
plt.title("Erreurs relatives des distances OSM/OdoMatrix")
plt.xlim(xmin=0)
plt.ylim(ymin=0)
Out[86]:
(0, 1.2000000000000002)