Touches essentielles du notebook

  • CTRL-ENTER pour exécuter une cellule et rester dedans.
  • ALT-ENTER pour exécuter une cellule en créer une autre en dessous et passer dedans.
  • MAJ-ENTER pour exécuter une cellule et passer dans celle de dessous.

Principes Généraux de Python

  • Indentation
  • typage : duck typing, garbage collection, références, collection
  • modèle de programmation : POO/fonctionnel/structuré
  • architecture : builtin/librairie standard/librairie annexe

Types

  • int
  • float
  • tuple
  • listes
  • chaines de caractères
  • dictionnaires

Entiers

In [5]:
1+1+1
Out[5]:
3
In [6]:
a=3
b=2
print("type de donnée :", type(a), "chaine supplémenaire")
print("addition :",a+b)
print("soustraction :", a-b)
print("multiplication :", a*b)
print("puissance :", a**b)
print("division euclidienne :",a//b)
print("reste :", a%b)
print("division :", a/b)
type de donnée : <class 'int'> chaine supplémenaire
addition : 5
soustraction : 1
multiplication : 6
puissance : 9
division euclidienne : 1
reste : 1
division : 1.5

Nombres flottants

In [7]:
a=3.5
b=2.8
print("type de donnée :", type(a))
print("addition :",a+b)
print("soustraction :", a-b)
print("multiplication :", a*b)
print("puissance :", a**b)
print("division euclidienne :",a//b)
print("reste :", a%b)
print("division :", a/b)
type de donnée : <class 'float'>
addition : 6.3
soustraction : 0.7000000000000002
multiplication : 9.799999999999999
puissance : 33.37263696900644
division euclidienne : 1.0
reste : 0.7000000000000002
division : 1.25

Pour la conversion.

In [8]:
a=1.5
print("type :", type(a), "valeur :", a)
b=int(a)
print("type :", type(b), "valeur :", b)
c=float(b)
print("type :", type(c), "valeur :", c)
type : <class 'float'> valeur : 1.5
type : <class 'int'> valeur : 1
type : <class 'float'> valeur : 1.0

Tuples

In [18]:
x=(1,2)
print("type de donnée :")
print(type(x), "valeur :", x)
type de donnée :
<class 'tuple'> valeur : (1, 2)

Accès au différents éléments.

In [11]:
print("premier élément :", x[0])
print("deuxième élément :", x[1])
premier élément : 1
deuxième élément : 2
In [8]:
y=(1,2,3,4,5,4,3,2,1)
print(y)
(1, 2, 3, 4, 5, 4, 3, 2, 1)
In [ ]:
y.
In [16]:
print("premier indexe où on à la valeur 5 :", y.index(5))
print("combien de fois a-t-on 4 :", y.count(4))
premier indexe où on à la valeur 5 : 4
combien de fois a-t-on 4 : 2
In [9]:
y[0]=2
---------------------------------------------------------------------------
TypeError                                 Traceback (most recent call last)
<ipython-input-9-336e692b378d> in <module>()
----> 1 y[0]=2

TypeError: 'tuple' object does not support item assignment

Listes

In [11]:
liste=[1,2,3,4,5,4,3,2,1]
print("type de donnée :", type(liste))
print("valeur :", liste)
type de donnée : <class 'list'>
valeur : [1, 2, 3, 4, 5, 4, 3, 2, 1]

Comme pour les tuple :

In [13]:
print("première valeur", liste[0])
print("dernière valeur :", liste[-1])
print("découpage :", liste[1:4])
print("découpage plus fin :", liste[1::2])
print("premier indexe où on à la valeur 5 :", liste.index(5))
print("combien de fois a-t-on 4 :", liste.count(4))
première valeur 1
dernière valeur : 1
découpage : [2, 3, 4]
découpage plus fin : [2, 4, 4, 2]
premier indexe où on à la valeur 5 : 4
combien de fois a-t-on 4 : 2

Différence : structure dynamique.

In [14]:
print("avant :", liste)
liste.append(2)
print("après :", liste)
avant : [1, 2, 3, 4, 5, 4, 3, 2, 1]
après : [1, 2, 3, 4, 5, 4, 3, 2, 1, 2]
In [15]:
print("avant :", liste)
c=liste.pop()
print("après", liste)
print("et on a récupéré la valeur manquante :", c)
avant : [1, 2, 3, 4, 5, 4, 3, 2, 1, 2]
après [1, 2, 3, 4, 5, 4, 3, 2, 1]
et on a récupéré la valeur manquante : 2

De nombreuses méthodes disponibles.
Utiliser la touche TAB après avoir tapé :

liste.
In [16]:
print("avant :", liste)
liste.sort()
print("après :", liste)
avant : [1, 2, 3, 4, 5, 4, 3, 2, 1]
après : [1, 1, 2, 2, 3, 3, 4, 4, 5]
In [17]:
print("avant :", liste)
liste.reverse()
print("après :", liste)
avant : [1, 1, 2, 2, 3, 3, 4, 4, 5]
après : [5, 4, 4, 3, 3, 2, 2, 1, 1]
In [18]:
print("avant :", liste)
liste.extend([1.5, 1.6, 1.7, 1.8])
print("après :", liste)
avant : [5, 4, 4, 3, 3, 2, 2, 1, 1]
après : [5, 4, 4, 3, 3, 2, 2, 1, 1, 1.5, 1.6, 1.7, 1.8]
In [19]:
print("avant :", liste)
liste.insert(2,-5)
print("après :", liste)
avant : [5, 4, 4, 3, 3, 2, 2, 1, 1, 1.5, 1.6, 1.7, 1.8]
après : [5, 4, -5, 4, 3, 3, 2, 2, 1, 1, 1.5, 1.6, 1.7, 1.8]
In [43]:
print("avant :", liste)
liste.remove(-5)
print("après :", liste)
avant : [5, 4, -5, 4, 3, 3, 2, 2, 1, 1, 1.5, 1.6, 1.7, 1.8]
après : [5, 4, 4, 3, 3, 2, 2, 1, 1, 1.5, 1.6, 1.7, 1.8]
In [20]:
tuple(liste)
Out[20]:
(5, 4, -5, 4, 3, 3, 2, 2, 1, 1, 1.5, 1.6, 1.7, 1.8)

On verra des techniques de construction plus élaborées au moment de la discussion des boucles.

Chaines de caractères

In [24]:
chaine="Journée CASCIMODOT"
print("type de valeur :", type(chaine))
print("valeur :", chaine)
type de valeur : <class 'str'>
valeur : Journée CASCIMODOT

Comme pour les tuples et les listes.

In [46]:
print("découpage :", chaine[1::2])
print("première occurence du c majuscule :", chaine.index('C'))
print("nombres d'occurences de la lettre O :", chaine.count('O'))
découpage : oré ACMDT
première occurence du c majuscule : 8
nombres d'occurences de la lettre O : 2

Utilisation d'autres déclarations

In [21]:
chaineBis = 'Journée CASCIMODOT'
chaineTierce = """Pour inclure plusieurs lignes
cette syntaxe est particulièrement pratique
comme on peut le constater"""
In [22]:
print(chaineTierce)
Pour inclure plusieurs lignes
cette syntaxe est particulièrement pratique
comme on peut le constater

Et pour obtenir de l'aide taper :

chaineTierce.split?

ENORMEMENT de méthodes disponible.

In [25]:
print(chaine)
print("mise en majuscule :", chaine.capitalize())
print("remplissage avec des caractères :", chaine.center(50,'*'))
print("recherche de sous-chaine", chaine.find('née'))
print("échange :", chaine.swapcase())
print("séparation autour d'un caractère (défaut espace)", chaine.split())
Journée CASCIMODOT
mise en majuscule : Journée cascimodot
remplissage avec des caractères : ****************Journée CASCIMODOT****************
recherche de sous-chaine 4
échange : jOURNÉE cascimodot
séparation autour d'un caractère (défaut espace) ['Journée', 'CASCIMODOT']

Possibilité d'inclure des variables.
syntaxe beaucoup plus riche que ce qui est montré ci dessous

In [31]:
a=2.0000008
b=1.2
c=1.3
message='Le prochaine {0} paragraphe {0} est le numéro {0:.2}'.format(a,b,c)
print(message)
Le prochaine 2.0000008 paragraphe 2.0000008 est le numéro 2.0

Conversions possibles.

In [32]:
a=int('11')
print("type :", type(a))
print("valeur :", a)
b=str(11)
print("type :", type(b))
print("valeur :", b)
type : <class 'int'>
valeur : 11
type : <class 'str'>
valeur : 11
In [69]:
chaine='abcdefghijklmnopqrstuvwxyz'
liste=list(chaine)
print("la liste est :", liste)
print('On peut la réunir :', "".join(liste))
print("En choisissant les séparateurs", "* *".join(liste))
la liste est : ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z']
On peut la réunir : abcdefghijklmnopqrstuvwxyz
En choisissant les séparateurs a* *b* *c* *d* *e* *f* *g* *h* *i* *j* *k* *l* *m* *n* *o* *p* *q* *r* *s* *t* *u* *v* *w* *x* *y* *z

Les listes stockent tout type de donnée.

In [70]:
liste=[[1,2,3], 'a', 1/5, 0.2, 12, "chaine".split()]
print(liste)
[[1, 2, 3], 'a', 0.2, 0.2, 12, ['chaine']]

Dictionnaires

Permettent d'indexer autrement que par des entiers. Permettent de coder une correspondance.

In [33]:
dico={'a':2, 'b':1, 'c':5, 'd':7, 2: 3}
print('type :', type(dico))
print("valeur :", dico)
type : <class 'dict'>
valeur : {'c': 5, 2: 3, 'b': 1, 'd': 7, 'a': 2}
In [34]:
print(dico['a'])
print(dico[2])
2
3
In [60]:
dico = dict(((1,2),(3,4),(5,6)))
print(dico)
print(dico[1])
{1: 2, 3: 4, 5: 6}
2

Nombreuses méthodes (taper dico. puis la touche de tabulation puis pour l'aide ajouter point d'interrogation).

Variables et affectations

références, affectation et unpacking+permutation

Unpacking.

In [35]:
a,b,c=1,2,3
print('plusieurs variables affectées en mêmes temps')
print('a :', a)
print('b :', b)
print('c :', c)
plusieurs variables affectées en mêmes temps
a : 1
b : 2
c : 3
In [81]:
liste=[1,2,3,4]
a,b,c,d = liste
print('a :', a)
print('b :', b)
print('c :', c)
print('d :', d)
a : 1
b : 2
c : 3
d : 4
In [36]:
liste=('a',1,2,'b','essai')
a, *b, c=liste
print('a :', a)
print('b :', b)
print('c :', c)
a : a
b : [1, 2, 'b']
c : essai

Mutation et références.

In [37]:
a=1
b=a
print(a,b)
a=2
print(a,b)
1 1
2 1
In [84]:
a=[1,2,3]
b=a
print(a,b)
a=[4,5,6]
print(a,b)
[1, 2, 3] [1, 2, 3]
[4, 5, 6] [1, 2, 3]
In [39]:
a=[1,2,3]
b=a
print(a,b)
a.append(4)
print(a,b)
[1, 2, 3] [1, 2, 3]
[1, 2, 3, 4] [1, 2, 3, 4]
In [41]:
a=a[1:4]
print(a,b)
[3, 4] [1, 2, 3, 4]
In [42]:
c=a.append(4)
print(c)
None

MORALITE : Pas de copie par défaut.

Fonctions

valeur par défaut arguments positionnels, arguments par mots clés, pass

Syntaxe élémentaire.

In [47]:
def maFonction(x):
    y=2*x
    return y
print(4)
4
In [49]:
maFonction(2)
Out[49]:
4
In [50]:
maFonction(2.5)
Out[50]:
5.0
In [51]:
maFonction((2,3))
Out[51]:
(2, 3, 2, 3)
In [52]:
maFonction([1,2,3])
Out[52]:
[1, 2, 3, 1, 2, 3]
In [53]:
maFonction("blabla")
Out[53]:
'blablablabla'

Arguments par défaut.

In [55]:
def puissance(n, p=2):
    return n**p
In [56]:
puissance(2,3)
Out[56]:
8
In [57]:
puissance(3)
Out[57]:
9
In [59]:
puissance(n=4, p=3)
Out[59]:
64
In [60]:
puissance(p=3, n=4)
Out[60]:
64

Docstring

In [61]:
def documentation():
    """Ceci est retournée par l'aide lorsqu'on la demande."""
    pass
In [62]:
documentation?

Attention lorsque l'agument par défaut est mutable.

In [63]:
def problematique(liste=[]):
    liste.append(1)
    return liste
    
In [64]:
problematique()
Out[64]:
[1]
In [66]:
problematique()
Out[66]:
[1, 1, 1]
In [67]:
problematique()
Out[67]:
[1, 1, 1, 1]
In [68]:
def problematiqueBis(liste=None):
    if liste is None:
        liste=list()
    liste.append(1)
    return liste
    
In [69]:
problematiqueBis()
Out[69]:
[1]
In [70]:
problematiqueBis()
Out[70]:
[1]

Test

booléens

In [71]:
print(type(True),type(False))
<class 'bool'> <class 'bool'>
In [73]:
a=1
test = (a==1)
print(type(test), test)
<class 'bool'> True
In [74]:
test2 = (a<=2.0)
print(test2)
True
In [75]:
def testBateau(a):
    if a==1:
        print("Ok")
    else:
        print("pas Ok")
In [76]:
testBateau(1)
testBateau(2)
Ok
pas Ok
In [77]:
def testAvance(a):
    if isinstance(a, type(" ")):
        print("Chaine de caractére")
    elif isinstance(a, type(1)):
        print("Entier")
    elif isinstance(a, list):
        print("Liste")
    else:
        print("pas clair")
        
            
In [78]:
testAvance(1)
Entier
In [79]:
testAvance([1,2,3])
Liste

Boucle while

In [83]:
def premier(n):
    i=2
    while i**2<n:
        if n%i != 0:
            i+=1
        else:
            print("Le nombre {} est composite".format(n))
    print("Le nombre {} est premier.".format(n))
In [81]:
premier(13)
Le nombre 13 est premier.
In [82]:
premier(100)
Le nombre 100 est composite

Boucle for

itération généralisées, condition else

In [84]:
liste = ['A', 1, [1,2,3]]
for element in liste:
    print(element)
A
1
[1, 2, 3]
In [86]:
uplet = (1,2,3,4,'a','b','bcd')
for element in uplet:
    print(element)
1
2
3
4
a
b
bcd

Itération sur des objets plus "compliqués".

In [87]:
for i in range(5):
    print(i)
0
1
2
3
4
In [88]:
type(range(5))
Out[88]:
range
In [89]:
dico = {'a':1, 'b':2, 'c':3}
for indice in dico:
    print(indice," : ", dico[indice])
c  :  3
b  :  2
a  :  1
In [90]:
for indice, valeur in dico.items():
    print(indice, " : ", valeur)
c  :  3
b  :  2
a  :  1
In [79]:
for valeur in dico.values():
    print(valeur)
2
1
3

Et quand on aurait besoin d'un indice.

In [91]:
liste= list('blablablablabla')
for i,lettre in enumerate(liste):
    print("indice {0} lettre {1} :".format(i, lettre))
indice 0 lettre b :
indice 1 lettre l :
indice 2 lettre a :
indice 3 lettre b :
indice 4 lettre l :
indice 5 lettre a :
indice 6 lettre b :
indice 7 lettre l :
indice 8 lettre a :
indice 9 lettre b :
indice 10 lettre l :
indice 11 lettre a :
indice 12 lettre b :
indice 13 lettre l :
indice 14 lettre a :

Discuter avantages itérateurs.

Compréhension de liste

In [92]:
liste=[i**2 for i in range(1,10)]
for nombre in liste:
    print(nombre)
1
4
9
16
25
36
49
64
81
In [93]:
liste=[i**2 for i in range(1,20) if i%3==1]
for nombre in liste:
    print(nombre)
1
16
49
100
169
256
361

Pour les trop grosses listes.

In [82]:
def est_premier(nb):
    for div in range(2,nb-1):
        if nb%div == 0:
            return False
    return True
    
In [83]:
for i in (i**2 for i in range(1,20) if est_premier(i)):
    print(i)
1
4
9
25
49
121
169
289
361

Fichiers

syntaxe standard par with

In [44]:
with open("test.txt", 'w') as aecrire:
    aecrire.write("première ligne?")
    aecrire.write("deuxième ligne?")
In [45]:
with open("test.txt", 'r') as alire:
    print(alire.read())
première ligne?deuxième ligne?
In [46]:
with open("test.txt", 'a') as arajouter:
    arajouter.write("\nNouvelle ligne si tout va bien")
In [50]:
with open("test.txt", 'r') as alire:
    print(alire.read())
première ligne?deuxième ligne?
Nouvelle ligne si tout va bien
In [3]:
with open("test.txt", 'r') as alire:
    for ligne in alire:
        print(ligne)
première ligne?deuxième ligne?

Nouvelle ligne si tout va bien

Là encore un objet fichier à de multiples méthodes.
Tester avec l'autocomplétion, ne pas oublier de fermer avec la méthode close.

Gestion des erreurs

try except, raise

In [94]:
def division(num, den):
    return num/den
In [95]:
division(1,0)
---------------------------------------------------------------------------
ZeroDivisionError                         Traceback (most recent call last)
<ipython-input-95-78dd29d37371> in <module>()
----> 1 division(1,0)

<ipython-input-94-6e247ed36ea1> in division(num, den)
      1 def division(num, den):
----> 2     return num/den

ZeroDivisionError: division by zero
In [96]:
def divisionCorrige(num, den):
    try:
        return num/den
    except ZeroDivisionError:
        print("Diviser par zéro c'est mal!")
        return None
In [97]:
divisionCorrige(1,0)
Diviser par zéro c'est mal!

MORALE : Mieux vaut demander pardon que la permission (en temps de calcul en tout cas)

Builtin

  • fonctionnel : map, lambda, filter, zip
  • manipulation : reversed, sorted, slice, enumerate, format
  • vectorisation : sum, max, min, round, len,
  • interaction basique utilisateur : print, input,

Librairies

import ou from import Exemples math, random, requests...

In [98]:
import math

On pourra tester l'appui de la touche TAB après avoir tapé :

math.
In [71]:
math.exp(2)+math.sin(math.pi)
Out[71]:
7.38905609893065
In [99]:
import random as rd
In [100]:
for i in range(5):
    print(rd.random())
0.9050920463816937
0.5204006599682303
0.34815214614001877
0.30724764384941183
0.16355652104826257
In [101]:
import copy
In [ ]:
copy.copy()
In [102]:
from copy import copy
In [103]:
a=[1,2,3,4]
b=copy(a)
print(a,b)
a.append(5)
print(a,b)
[1, 2, 3, 4] [1, 2, 3, 4]
[1, 2, 3, 4, 5] [1, 2, 3, 4]

Lenteur relative

Ordre usuel :

  1. Prototypage,
  2. Profilage (%%timeit, %%prun, line_profiler),
  3. Optimisation (numpy, numba, pypy, cython, cffi)

Vectorisation du code.

In [104]:
def carree(M):
    n=len(M)
    resultat=list()
    for i in range(n):
        resultat.append(list())
        for j in range(n):
            S=0
            for k in range(n):
                S+=M[i][k]*M[k][j]
            resultat[i].append(S)
    return resultat
        
In [105]:
M=[[1,2,3],[4,5,6],[7,8,9]]
print(M)
print(carree(M))
[[1, 2, 3], [4, 5, 6], [7, 8, 9]]
[[30, 36, 42], [66, 81, 96], [102, 126, 150]]
In [106]:
n=300
M=[list(range(n)) for i in range(n)]
In [107]:
%%timeit
carree(M)
1 loops, best of 3: 6.55 s per loop
In [108]:
import numpy as np
In [109]:
def carreeBis(M):
    return M*M
In [111]:
def creation(n):
    return np.matrix(np.tile(np.arange(n),n).reshape((n,n)))

creation(10)
Out[111]:
matrix([[0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
        [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]])
In [112]:
M=creation(200)
In [113]:
%%timeit
carreeBis(M)
100 loops, best of 3: 8.61 ms per loop

Numba

In [115]:
from numba import jit
In [116]:
@jit
def carreeTierce(M):
    n,m=M.shape
    assert n==m
    resultat=np.zeros((n,n))
    for i in range(n):
        for j in range(n):
            S=0
            for k in range(n):
                S+=M[i,k]*M[k,j]
            resultat[i,j]=S
    return resultat
In [117]:
M=creation(200)
In [118]:
%%timeit
carreeTierce(M)
The slowest run took 52.30 times longer than the fastest. This could mean that an intermediate result is being cached 
1 loops, best of 3: 10.2 ms per loop

Ecosystème

Quelle librairie utiliser? exemples. urllib2/requests, matplotlib/bokeh, beautiful soup/lxml...

Non dits

  • syntaxe avancée : keywords et arguments positionnels, générateurs, itérateurs, décorateurs
  • parallélisme et le GIL
  • debugging
  • POO