python avanc e - prepas.orgprepas.org/2013/info/luminy/python-mardi/defalco-cours-avances.pdf ·...
TRANSCRIPT
Python avance
Marc de FalcoMaths/Info en MPSI
Centre International de Valbonne
7 mai 2013
A propos de cette presentation
On parlera ici d’extensions du langage.
Pour la culture plus que l’enseignement direct.
Items presentes :
1 les slices2 les list/dict par comprehension3 les generateurs4 les decorateurs5 les proprietes pour les objets6 la surcharge d’operateurs7 heritage
Presentation de Python
Python est un langage qui evolue :
par tout petits sauts
les PEP : Python Extension Proposal
l’objectif est toujours le meme :
moins de codemoins de repetitionplus clairplus efficace
import this :
There should be one– and preferably only one –obvious way todo it.Although that way may not be obvious at first unless you’reDutch.
Les slices (1/2)
Les slices permettent d’acceder a des sous listes par copie !
>>> l = [0,1,2,3,4,5,6,7,8,9]
>>> l[3:5] # l[debut:fin exclue]
[3, 4]
>>> l[:5] # debut = 0
[0, 1, 2, 3, 4]
>>> l[7:] # fin = len(l)
[7, 8, 9]
>>> l[:] # toute la liste, mais c’est une copie!!!
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
>>> l[0:8:2] # pas
[0, 2, 4, 6]
>>> l[::-1] # pas negatif il inverse debut/fin
[9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
Les slices (2/2)
On peut s’en servir pour faire des affectations
>>> l = list(range(10))
>>> l[3:5] = l[7:9]
>>> l
[0, 1, 2, 7, 8, 5, 6, 7, 8, 9]
# Tour de magie Pythonesque, que se passe t’il ?
>>> l = list(range(10))
>>> l[::2], l[1::2] = l[1::2], l[::2]
>>> l # a ne surement pas montrer aux eleves ;-)
Listes par comprehension
>>> [ 2 * i for i in range(5) ]
[0, 2, 4, 6, 8]
>>> [ [ i ** j for j in range(2,4) ]
for i in range(2,4) ]
[[4, 8], [9, 27]]
>>> [ i for i in range(10) if i % 2 == 0 ]
[0, 2, 4, 6, 8]
Dictionnaires
Les dictionnaires sont des tables de hachage
>>> d = {}
>>> d[0] = 1
>>> d[’cle’] = [1,2]
>>> d
{0: 1, ’cle’: [1,2]}
>>> 0 in d
True
>>> d[0]
1
>>> d[1]
[...]KeyError: 1
>>> d.get(1, -1)
-1
>>> for k in d:
... print(k, d[k])
0 1
cle [1,2]
>>> d.keys()
dict_keys([0, ’cle’])
>>> d.values()
dict_values([1, [1, 2]])
>>> d.items()
dict_items([(0, 1),
(’cle’, [1, 2])])
>>> for k, v in d.items():
... print(k, v)
Dicts par comprehension
>>> phrase = ’ceci est une phrase’
>>> freq = { c:s.count(c) for c in map(chr,
range(ord(’a’),ord(’z’)+1)) }
>>> freq
{’a’: 1, ’c’: 2, ’b’: 0, ’e’: 4, ’d’: 0, ’g’: 0,
’f’: 0, ’i’: 1, ’h’: 1, ’k’: 0, ’j’: 0, ’m’: 0,
’l’: 0, ’o’: 0, ’n’: 1, ’q’: 0, ’p’: 1, ’s’: 2,
’r’: 1, ’u’: 1, ’t’: 1, ’w’: 0, ’v’: 0, ’y’: 0,
’x’: 0, ’z’: 0}
ne sert pas souvent, mais parfois permet de remplacer 10 lignesmoches par une jolie ligne
Les generateurs (1/3)
Un generateur est une fonction qui peut
s’interrompre,
renvoyer un resultat,
puis reprendre la ou elle s’etait arretee
Le mot cle pour s’interrompre yield.On peut naturellement utiliser un generateur comme iterable :
for e in generateur:
print(e)
Les generateurs (2/3)
1 → 11 → 21 → 1211 → . . .
import itertools
def feedback():
s = ’1’
while True:
yield s
s = ’’.join( str(len(list(v)))+k
for k,v
in itertools.groupby(s) )
s = feedback()
print(next(s))
print(next(s))
Les generateurs (3/3)
Crible
def premier():
n = 10000
crible = [ True ] * n
for i in range(2,n):
if crible[i]:
for j in range(2,n//i):
crible[i*j] = False
sum(1/p for p in premier(1000))
[ p ** 2 for p in premier(10) ]
Les decorateurs
Un decorateur est un transformeur de fonction.
@trace
def fact(n):
if n == 0: return 1
return n * fact(n-1)
fact(3)
fact <- 3
fact <- 2
fact <- 1
fact <- 0
fact -> 1
fact -> 1
fact -> 2
fact -> 6
Les decorateurs
L’envers du decor :
def trace(func):
def wrapped(arg):
print("{} <- {}".\
format(func.__name__, repr(arg)))
retour = func(arg)
print("{} -> {}".\
format(func.__name__, repr(retour)))
return retour
return wrapped
Les proprietes
C’est une decoration de methode qui permet de definir des accestypes attribut :
import math
class Cercle:
def __init__(self, rayon):
self.rayon = rayon
@property
def aire(self):
return math.pi * self.rayon ** 2
c = Cercle(5)
print(c.aire)
Les proprietes
Pour avoir la propriete en ecriture on rajoute
class Cercle:
(...)
@aire.setter
def aire(self, a):
self.rayon = math.sqrt(a) / math.pi
c = Cercle(5)
c.aire = 100
print(c.rayon)
La surcharge d’operateurs
Pour chaque operation sur les objets, il faut definir une methodeau nom predefini.Exemple : __add__ pour pouvoir faire o1+o2
class IntMod33:
def __init__(self,n):
self.n = n % 33
def __add__(self,other):
return IntMod33((self.n+other.n))
o1 = IntMod33(127)
o2 = IntMod33(73)
print( (o1+o2).n )
La surcharge d’operateurs
Une surchage pratique :
class IntMod33: (...)
def __str__(self):
return str(self.n)
print(IntMod33(127))
Difference avec __repr__.
La surcharge d’operateurs
Iterer sur un objet : il suffit de definir __iter__ comme ungenerateur
class Etsil:
def __init__(self,l):
self.l = list(l)
def __iter__(self):
for e in reversed(self.l):
yield e
l = Etsil(range(5))
for e in l:
print(e)
L’heritage
Un objet peut heriter d’un autre objet.Syntaxe : class Fille(Mere):
Tous les attributs/methodes non redefinis sont herites.On peut faire reference aux methodes de sa mere.Syntaxe : super(Fille,self) soit en tant que Mere
L’heritage
class A:
def f(self):
return 3
class B(A):
def f(self):
return 1 + super(B,self).f()
b = B()
print(b.f())
L’heritage multiple
L’approche Pythonesque : mixins
class PossedeValeur:
def __init__(self,v):
self.valeur = v
class AfficheValeur(PossedeValeur):
def __str__(self):
return str(self.valeur)
class AjouteValeur(PossedeValeur):
def __add__(self,o):
# ici type(self) est le meilleur type
return type(self)(o.valeur+self.valeur)
class Mixin(PossedeValeur,
AfficheValeur,AjouteValeur): pass
m = Mixin(42)
print(m+m)
Il en reste...
Principalement les meta-classes qui permettent de fabriquer desclasses.Exemple en django (framework web) :
Une classe pour decrire une relation du modele relationnel
Une meta-classe en deduit une classe de manipulation sur labase de donnee automatiquement