Python avancé

publicité
Python avancé
Marc de Falco
Maths/Info en MPSI
Centre International de Valbonne
7 mai 2013
A propos de cette présentation
On parlera ici d’extensions du langage.
Pour la culture plus que l’enseignement direct.
Items présentés :
1
2
3
4
5
6
7
les slices
les list/dict par compréhension
les générateurs
les décorateurs
les propriétés pour les objets
la surcharge d’opérateurs
héritage
Présentation de Python
Python est un langage qui évolue :
par tout petits sauts
les PEP : Python Extension Proposal
l’objectif est toujours le même :
moins de code
moins de répétition
plus clair
plus efficace
import this :
There should be one– and preferably only one –obvious way to
do it.
Although that way may not be obvious at first unless you’re
Dutch.
Les slices (1/2)
Les slices permettent d’accèder à des sous listes par copie !
>>>
>>>
[3,
>>>
[0,
>>>
[7,
>>>
[0,
>>>
[0,
>>>
[9,
l = [0,1,2,3,4,5,6,7,8,9]
l[3:5] # l[debut:fin exclue]
4]
l[:5] # debut = 0
1, 2, 3, 4]
l[7:] # fin = len(l)
8, 9]
l[:] # toute la liste, mais c’est une copie!!!
1, 2, 3, 4, 5, 6, 7, 8, 9]
l[0:8:2] # pas
2, 4, 6]
l[::-1] # pas negatif il inverse debut/fin
8, 7, 6, 5, 4, 3, 2, 1, 0]
Les slices (2/2)
On peut s’en servir pour faire des affectations
>>>
>>>
>>>
[0,
l = list(range(10))
l[3:5] = l[7:9]
l
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 compréhension
>>> [ 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 compréhension
>>> 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’:
’f’: 0, ’i’: 1, ’h’: 1, ’k’: 0, ’j’: 0, ’m’:
’l’: 0, ’o’: 0, ’n’: 1, ’q’: 0, ’p’: 1, ’s’:
’r’: 1, ’u’: 1, ’t’: 1, ’w’: 0, ’v’: 0, ’y’:
’x’: 0, ’z’: 0}
0,
0,
2,
0,
ne sert pas souvent, mais parfois permet de remplacer 10 lignes
moches par une jolie ligne
Les générateurs (1/3)
Un générateur est une fonction qui peut
s’interrompre,
renvoyer un résultat,
puis reprendre là où elle s’était arretée
Le mot clé pour s’interrompre yield.
On peut naturellement utiliser un générateur comme itérable :
for e in generateur:
print(e)
Les générateurs (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 générateurs (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 décorateurs
Un décorateur est un transformeur de fonction.
@trace
def fact(n):
if n == 0: return 1
return n * fact(n-1)
fact(3)
fact
fact
fact
fact
fact
fact
fact
fact
<<<<->
->
->
->
3
2
1
0
1
1
2
6
Les décorateurs
L’envers du décor :
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 propriétés
C’est une décoration de méthode qui permet de définir des accès
types 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 propriétés
Pour avoir la propriété en écriture 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’opérateurs
Pour chaque opération sur les objets, il faut définir une méthode
au nom prédéfini.
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’opérateurs
Une surchage pratique :
class IntMod33: (...)
def __str__(self):
return str(self.n)
print(IntMod33(127))
Diffèrence avec __repr__.
La surcharge d’opérateurs
Itérer sur un objet : il suffit de définir __iter__ comme un
générateur
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’héritage
Un objet peut hériter d’un autre objet.
Syntaxe : class Fille(Mere):
Tous les attributs/méthodes non redefinis sont hérités.
On peut faire référence aux méthodes de sa mère.
Syntaxe : super(Fille,self) soit en tant que Mere
L’héritage
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’héritage 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 des
classes.
Exemple en django (framework web) :
Une classe pour décrire une relation du modèle relationnel
Une meta-classe en déduit une classe de manipulation sur la
base de donnée automatiquement
Téléchargement