if __name__ == `__main__`

Transcription

if __name__ == `__main__`
Formation Python
Traitement et visualisation de données scientifiques
Jour 1 – Le langage
Fernando NIÑO
Legos/IRD
Janvier 22-30
2009
Jour 1
Formation Python
Python - Le Langage
Introduction
Présentation
Python vs Les autres
Python vs Perl
Travailler avec Python
Le Langage
2
© 2009 Fernando NIÑO
Les langage Python
• Orienté objet
– facilite la décomposition et la réutilisation
• Syntaxe claire
– Pas de raccourcis « magiques » incompréhensibles,
chers aux utilisateurs Perl (i.e. $<, $_, ...).
• Facile à appréhender
– Ca, on verra...
• Trois utilisations type:
– script
– programme à part entière
– de la colle
3
© 2009 Fernando NIÑO
Python vs. les autres
Langage
Nombre d’instructions p.r. à C
C
1
C++
2.5
Fortran
2.5
Java
2.5
MS Visual Basic
4.5
Perl
6
Python
6
Smalltalk
6
Expressivité des langages
(Code complete , Steve McConnell.)
© 2009 Fernando NIÑO
4
Ce qu’on retient
• Python, c’est chic !
• Trois modes:
– script (remplace bash)
– programmation (remplace C)
– de la colle (permet de donner un visage unifié à un amas
de code)
5
© 2009 Fernando NIÑO
Jour 1 – Le langage
Formation Python
Python - Le Langage
Présentation
Installation
Les versions
Travailler avec Python
Les modules
Python 3.0
Prise en main
PYTHONPATH
Le Langage
6
© 2009 Fernando NIÑO
Travailler avec Python
• Beaucoup de modules disponibles
– sur le web
– sur CheeseShop:
http://pypi.python.org
• Mode script
– mode « production » quand on a un programme qui
marche
– mode « batch » classique (csh, bash, awk,....)
• Mode interactif
– Facile à déboguer : avantages des langages de script
– pas de phase de compilation/éxecution
– on peut tester en ligne de commande directement
– exploration du langage / des données
7
© 2009 Fernando NIÑO
Installation de Python
• Enthought Python Distribution est installé
– http://www.enthought.com/products/epd.htm
• Les versions:
–
–
–
–
–
–
–
Python (un alias vers...)
Python 2.4 (30/12/2004)
Python 2.5 (2.5.4 le 23/12/2008)
Python 2.6 (1/10/2008)
Python 3.0 (3/12/2008)
Win32 Python – adapté pour Windows
IronPython (v1: 09/2006; v2: 12/2008) - .NET framework
• Les modules
– si python pur:
python setup.py install
– ou
easy_install <module>
Index)
# Cherche PyPI (Package
8
© 2009 Fernando NIÑO
Python 3.0 - Version incompatible
• print devient une fonction,
– from __future__ import print_function
• Unification des types texte vers UNICODE.
• Type bytes and bytearray;
• Elimination de compatibilité ancienne:
–
–
–
–
old-style classes
integer-truncating division (1/2=0 ==> 1/2=0.5 & 1//2=0
string exceptions
implicit relative imports.
• Outil de conversion 2to3
– http://docs.python.org/3.0/whatsnew/3.0.html
9
© 2009 Fernando NIÑO
Prise en main python
• Trouvez l’interpreteur Python
EPD with Py2.5 (4.0.30002 ) -- http://
www.enthought.com/epd
Python 2.5.2 |EPD with Py2.5 4.0.30002 |
(r252:60911, Oct 15 2008, 16:58:38)
[GCC 4.0.1 (Apple Computer, Inc. build 5370)] on
darwin
Type "help", "copyright", "credits" or "license" for
more information.
>>>
• Faites quelque chose !
>>> print "Je fais quelque chose"
Je fais quelque chose
>>>
• ctrl-D pour sortir
10
© 2009 Fernando NIÑO
Installation des modules Python
• En pratique: pour python interactif il existe
IPython (ipython.scipy.org)
• Mais....c’est un module. Installons-le:
cd ipython-0.7.2
python setup.py install --prefix=d:\python
– ou
python setup.py install --home=/home/moi
• Par défaut, les modules sont installés dans
l’arborescence de l’installation python utilisée:
/usr/lib/python2.5/site-packages
• En windows, l’installateur pose la question...
11
© 2009 Fernando NIÑO
Installation mpmath
• Installation standard d’un paquetage:
cd mpmath
python setup.py install
• Test:
ipython -pylab
import mpmath
from mpmath import sin, cos, exp
mpmath.cplot(lambda z: mpmath.exp(1/z), [-2, 2],
[-2, 2])
mpmath.plot([cos, sin], [-4, 4])
mpmath.cplot(sin,[-5, 5], [-5,5])
12
© 2009 Fernando NIÑO
mpmath test
• On peut taper tout le code
ou
ipython
import mpmathtest
puis, editez le fichier en changeant la ligne commentée
import mpmathtest
comportement ? Appréciez fichier .pyc
help reload
13
© 2009 Fernando NIÑO
PYTHONPATH
• Les scripts python utilisent en général des modules
python (pour ne pas réinventer la roue).
– Un module est un objet chargé par l’interpréteur Python
à partir d’un fichier texte qui regroupe des variables,
classes et fonctions. En général, c’est un fichier .py
• Comment se fait la recherche des modules ?
– Dans le répertoire courant
– Installé a posteriori : vérifie la variable PYTHONPATH
– Python Standard Library (PSL) : fournit avec l’installation
Python
• PSL:
– une installation « administrateur » se fait à l’intérieur de
l’installation Python
/usr/lib/python2.5/site-packages
14
© 2009 Fernando NIÑO
Vérification de l’environnement
• Les chemins de recherche de Python
>>> import sys
>>> sys.path
['', '/System/Library/Frameworks/Python.framework/
Versions/2.3/lib/python23.zip', ...,'/System/
Library/Frameworks/Python.framework/Versions/2.3/
Extras/lib/python']
>>> exit
'Use Ctrl-D (i.e. EOF) to exit.'
>>> ^D
15
© 2009 Fernando NIÑO
Documentation python
• Sur *nix:
pydoc -p 7464
http://localhost:7464/
• Sur Windows: chercher
d:\Python\Tools\Scripts\pydocgui
16
© 2009 Fernando NIÑO
Ce qu’on retient
• On utilise Python 2.5 car c’est le plus stable: 2.6 est
une version de transition, mais Enthought ne le
fournit pas encore
• La version 2.6 est de transition vers Python 3.0
• Python 3.0 est incompatible avec 2.x : il faut
attendre 1-3 ans à que les librairies scientifiques
soient compatibles.
• PYTHONPATH et sys.path sont très importants
• python setup.py install
• import xxxx permet d’utiliser xxxx.fonction
17
© 2009 Fernando NIÑO
Jour 1
Formation Python
Python - Le Langage
Présentation
Travailler avec Python
Les bases du langage
Structures de données
Contrôle du flux d'exécution
Gestion des fichiers
Le Langage
Encapsulation
POO
Dérivation
Réutilisation
Gestion des erreurs
Exceptions
Logger
18
© 2009 Fernando NIÑO
Le langage
• C’est un langage dynamique:
– toutes les instructions sont exécutées au fur et à mesure,
y compris les déclarations.
import sys
# Module d’accès au systeme
Instruction
print sys.path
Commentaire
monchemin=’/sw/lib/’
sys.path.append(monchemin)
print sys.path
– on peut modifier le chemin de recherche de modules,
comme avec PYTHONPATH.
Variable
• C’est un langage où l’indentation est significative
import sys
print sys.path
#---> ERREUR de syntaxe
19
© 2009 Fernando NIÑO
L’indentation
• L’indentation est celle de l’utilisateur: n espaces
d’indentation.
– C’est bien: ce qu’on voit est ce qu’il éxecute (pas de
problème d’accolade fermée trop tôt comme en C...)
for(i=0; i < n; i++) {
for (j=0; j < n; j++)
x=x*j;
y=y*i+j;
}
piège
for i in range(0,n):
for j in range(0,n):
x=x*j
y=y*i+j
20
© 2009 Fernando NIÑO
L’indentation (2)
• Le problème:
– quand il y a plusieurs personnes qui éditent un
programme
– quand on mélange les éditeurs (configuration de largeur
de TAB différentes)
– ...mais seulement si on utilise des tabulations
• La solution: pas de tabulations !!!!!!
– chaque editeur à sa solution
(setq indent-tabs-mode nil)
(setq-default tab-width 4)
set tabstop=4
set expandtab
#
;; dans EMACS
Dans .vimrc
21
© 2009 Fernando NIÑO
L’encodage
• Le problème:
– lorsqu’on a un fichier quelconque, on ne sait pas
comment interpréter son contenu:
– binaire ?
– big endian / little endian ?
– ASCII/ EBCDIC/Unicode ???
– il faut toujours des métadonnées
• Par défaut, l’interpreteur Python veut son code en
ASCII (encodage.py) (UTF-8 pour Py3k).
• Si l’on veut autre chose, il faut utiliser l’entete:
#!/usr/bin/env python
# -*- coding: iso-8859-15 -*...
Première ou deuxième ligne
obligatoirement
22
© 2009 Fernando NIÑO
Références
• Dans ce qui suit (syntaxe du langage), les
références utilisées sont
– Programmation Python
Tarez Ziadé, Ed. Eyrolles 2006
– Learning Python (3eme Ed)
Mark Lutz Ed. O’Reilly 2007
- Python Scripting for Compuational Science
Hans-Peter Langtangen, Springer 2008
23
© 2009 Fernando NIÑO
Les littéraux
• Alphanumériques
– Chaînes simples:
print “Ceci est une chaîne simple, Python gère
Unicode à partir de la version 2.4”
– Chaînes triplées
print ”””Voici les trois paires de guillemets qui
permettent d’écrire plusieurs lignes
sans avoir a concatener les chaînes”””
– Chaînes Unicode
print u”Ont un prefixe U ou u”
– Chaînes “brutes” (ou raw)
print r'Eliminent l\'interpretation de backslash\n'
Eliminent l\'interpretation de backslash\n
print 'Eliminent l\'interpretation de backslash\n'
Eliminent l'interpretation de backslash
24
© 2009 Fernando NIÑO
Texte et Python 3.0
• Dans Python3.0 il y a deux types de données:
– texte : type str
– données : type bytes
• C’est tout ! Tout est en unicode; le melange de str
et bytes donnce TypeError
• Bonne simplification, mais le code ancien en
souffre.
• L’encodage de la source est par défaut UTF-8
25
© 2009 Fernando NIÑO
Les littéraux
• Numériques
– entiers simples ou longs: conversion automatique à partir
de Python 2.4:
In [34]:
In [35]:
Out[35]:
In [36]:
In [37]:
Out[37]:
In [38]:
Out[38]:
In [39]:
In [40]:
Out[40]:
i=1000
type(i)
<type 'int'>
i=i*i*i*i*i
i
1000000000000000L
type(i)
<type 'long'>
i=1000
type(i)
<type 'int'>
26
© 2009 Fernando NIÑO
Les entiers en Python 3.0
• Correction d’ambiguités: x/y = ???
– x=1
– y=2
– x/y = 0
– x=1
– y=2.0
– x/y = 0.5
• Dans Python 2.x:
– 1/2 = 0
• Dans Python 3.0
– 1/2 = 0.5
– 1//2=0
27
© 2009 Fernando NIÑO
(Parenthèse: les types)
• Python est un langage faiblement typé
– Donc, le type d’une variable dépend de son contenu
i=10
# i est un entier
i=’voici’ # i est une chaîne de caractères
• Pour avoir des informations sur un objet:
– Son type
type(i)
– De quoi est-il capable (méthodes applicables) ?
dir(i)
• Avec ipython
?i
• Le syndrome du canard (“duck-typing”)
– si ça marche comme un canard et fait coing-coing, c’est un
canard.
28
© 2009 Fernando NIÑO
Les littéraux
• Numériques
– virgule flottante (comme d’habitude...)
x=0.001
y=1.2E-9
– nombres complexes notation génie électrique:
u=5j # pour ne pas confondre avec le courant
v=3 + 4.5j
• Exercice:
– avec python faites
type(u), type(v), type(x), u+v, dir(u+v)
– avec dir, quelles fonctions remarque-t-on ?
– avec ipython faites la même chose et en plus:
?u
29
© 2009 Fernando NIÑO
Première approche de IPython
• Avec ? ou ?? vous obtenez des renseignements sur
un objet
• Avec tabulation vous complétez les mots
import sys
sys.<TAB>
sys.pa<TAB>
• Un bon mécanisme de historique (ctrl-n, ctrl-p, hist,
hist -n)
30
© 2009 Fernando NIÑO
Ce qu’on retient
• L’indentation est significative
• On indique l’encodage au début
#!/usr/bin/env python
# encoding: utf-8
• Langage faiblement typé: une variable peut changer
de type en cours de route
• Le syndrome du canard
– si ça marche comme un canard et fait coing-coing, c’est un
canard.
• ipython
– variable? # donne des informations
– var<TAB> # complète
– %pdb
# Variable magique invoque le debogueur
31
© 2009 Fernando NIÑO
Formation Python
Python - Le Langage
Présentation
Travailler avec Python
Les bases du langage
Structures de données
Contrôle du flux d'exécution
Gestion des fichiers
Le Langage
Encapsulation
POO
Dérivation
Réutilisation
Gestion des erreurs
Exceptions
Logger
32
© 2009 Fernando NIÑO
Les types standard
• Valeur unique
None
# Absence de valeur (faux en calcul booléen)
• Nombres entiers
int
long
bool
• Virgule flottante
– toujours double précision (code C sous-jacent)
• Decimal (librairie standard >= 2.4)
– representation exacte
– interaction entiers et decimal uniquement
import decimal
dir(decimal) # peu de fonctions (pas de trigo.)
33
© 2009 Fernando NIÑO
Les types standard
• Les séquences
– collection finie d’éléments ordonnés
– accessibles par indexation
i=sequence[n]
– indexation négative: à partir du dernier
– tranches: index min et max et pas
sous-seq=sequence[min:max] # ou [debut::pas]
– Primitives de séquences:
len(), min(), max(),sum()
• Exercice:
– utilisant range et
premiers entiers
xrange calculez la somme des 57
34
© 2009 Fernando NIÑO
Solution
In [34]: seq=range(0,100)
In [35]: print sum(seq[0:58])
1653
In [36] : sum(xrange(58))
1653
– Vérification: somme(N)=N(N+1)/2
In [36]: print 57*58/2
1653
35
© 2009 Fernando NIÑO
Les chaînes de formatage
• Pour ceux qui connaissent C, c’est pareil ...
• Pour ceux qui ne connaissent pas....
– On remplace un indicateur de format %x par la valeur
indiqué.
In [1]: nom='Butterfly'
In [2]: print "Bonjour madame %s" % nom
Bonjour madame Butterfly
– Si plusieurs indicateurs de format, on utilise des tuples
In [4]: x = 3.45
In [5]: print 'Bonjour madame %s, votre avoir est de %.2f
EUR' % (nom,x)
Bonjour madame Butterfly, votre avoir est de 3.45 EUR
36
© 2009 Fernando NIÑO
Les chaînes de formatage
• Les indicateurs les plus utilisés:
%s
%f
%e
# pour les strings
# pour les virgule flottante
# virgule flottante notation scientifique
• Largeur.Precision
– Comme dans fortran, pour les valeurs à virgule flottante
on peut avoir une largeur et une précision d’affichage
In [6]: x=3.45435
In [7]: print '%08.2f' % x
00003.45
37
© 2009 Fernando NIÑO
Tuples
• Ce sont des séquences qui ont des éléments
hétérogènes
• ils ne peuvent pas être modifiés
– donc, copie si modification nécessaire
In [20]: tuple=('un',1,'deux',2)
In [21]: tuple[2]='3'
--------------------------------exceptions.TypeError
Traceback (most recent call last)
38
© 2009 Fernando NIÑO
Listes
• La seule séquence modifiable est la liste: Comme
le tuple, mais se créé avec des [ ]
liste=[]
liste = range(0,100)
# vide
# déjà vu
• Opérations interessantes:
liste.append(element)
liste.extend(liste2)
liste.insert(position,element)
liste.remove(element)
liste.pop(position)
liste.index(element)
liste.count(element)
liste.sort()
liste.reverse()
39
© 2009 Fernando NIÑO
Listes
• La seule séquence modifiable est la liste: Comme
le tuple, mais se créé avec des [ ]
liste=[]
liste = range(0,100)
# vide
# déjà vu
• Opérations interessantes:
Syntaxe ‘.’ de la POO: équivalent à
liste.append(element)
append(liste,element)
liste.extend(liste2)
liste.insert(position,element)
liste.remove(element)
liste.pop(position)
liste.index(element)
liste.count(element)
liste.sort()
liste.reverse()
© 2009 Fernando NIÑO
39
Exercice
• Créer une liste de nombres comme ceci:
– 0 à 10
– 50 à 80
– 90 à 100
• obtenir une sous-liste avec tous les nombres pairs
• les présenter du plus grand au plus petit
40
© 2009 Fernando NIÑO
Solution
liste=range(0,10) # ou =list(xrange(0,10))
liste.extend(range(50,80))
liste.extend(range(90,100))
liste
len(liste)
# Nombres pairs
pairs=liste[::2]
# Que se passe-t-il si l’on fait
liste[::2].reverse()
#ou si l’on fait
pairs_inverse=pairs.reverse()
41
© 2009 Fernando NIÑO
Les dictionnaires
• Dictionnaires, mappings ou hash
• associations de clés et valeurs
In [23]: dict={'a':’Sara’, 'b':’Mathilde’,
'c':None }
In [24]: dict
Out[24]: {'a': ‘Sara’, 'c': None, 'b': ‘Mathilde’}
– Remarquez que l’ordre est quelconque
• Pour le parcourir
In [25]:
Out[25]:
In [26]:
Out[26]:
In [27]:
Out[27]:
dict.keys()
['a', 'c', 'b']
dict.values()
[1, None, 2]
dict['b']
2
42
© 2009 Fernando NIÑO
Les dictionnaires
• Opérations courantes
– Insertions
dict={}
# Sans cela, ERREUR !!
dict['b']=’Eric’
dict
dict['b']=3
dict
– Test
dict.has_key('b')
dict.has_key('a')
– Parcours (en Python 3.0 ce ne sont plus de listes !)
dict.items()
dict.keys()
dict.values()
43
© 2009 Fernando NIÑO
Dictionnaires - exemples
• Exemple : traitement d’une liste de fichiers
– nous avons une liste de noms de fichiers avec répétitions
– il faut les traiter seulement une fois.
liste=['un','deux','trois','deux','un']
traites={}
for fichier in liste:
if traites.has_key(fichier):
pass
else:
print "Fichier %s traite" % fichier
traites[fichier]=True
44
© 2009 Fernando NIÑO
Les blocs, les variables
• Sont identifiés par l’indentation et commencent par
un ‘:’
for i in range(0,5) :
print “je suis dans un bloc”
print “j’imprime %d” % i
• Les variables sont des chaîne de caractères
alphanumériques:
Jesuisunevariable=1
JESUIS_une-variable=2
BREF_rien_d’anormal=3
# Erreur:‘-’ est un opérateur
# Erreur: l’apostrophe...
45
© 2009 Fernando NIÑO
Ce qu’on retient
• Listes: [ a,b,c] opérations
– append()
– slicing
• Tuples: (a,b,c) immuables: utilisés pour param.
• Dictionnaires: { a:1, b:2, c:3 } associations
– has_key()
– values()
– keys()
• Blocs: delimités par deux-points ‘:’
for line in f.readlines():
print line
46
© 2009 Fernando NIÑO
Formation Python
Python - Le Langage
Présentation
Travailler avec Python
Les bases du langage
Structures de données
Contrôle du flux d'exécution
Gestion des fichiers
Le Langage
Encapsulation
POO
Dérivation
Réutilisation
Gestion des erreurs
Exceptions
Logger
47
© 2009 Fernando NIÑO
Les boucles for (encore)
• On a déjà vu les boucles for
for i in liste:
print i
# Même syntaxe que bash
• Il existe des clauses break et continue
for i in listenum:
if (i > 0):
continue
print “i est negatif”
if (i == 0):
break
for i in range(0,6):
print i
else:
print "fin"
48
© 2009 Fernando NIÑO
Les conditionnels
• On l’a vu...cela s’appelle if
if i > 3:
print “plus grand que 3”
elif i > 10:
print “plus grand que 10”
else:
print “plus petit que 3”
49
© 2009 Fernando NIÑO
Les boucles while
• Classiques
while i < 4:
print i
else:
print “c’est fini”
– la clause else est exécutée à la fin de la boucle (sauf si
break)
– continue existe aussi, comme pour le for
50
© 2009 Fernando NIÑO
Structure d’un programme
• La structure d’un programme est en général:
– déclaration des librairies utilisées
– définition des fonctions utilisateur
– programme principal
import sys
def maroutine(param1,param2):
param1=sys.path
sys.path.append(param2)
x=None
maroutine(x,'/home/fnino/python2.3')
sys.path
51
© 2009 Fernando NIÑO
Gabarit d’un script simple
#!/usr/bin/env python
# encoding: utf-8
"""
untitled.py : gabarit simple
Created by Fernando NIÑO on 2009-01-19.
"""
import sys
import os
def main():
pass
if __name__ == '__main__':
main()
52
© 2009 Fernando NIÑO
Import
• Python est un langage dynamique
• import est une commande comme une autre !
• On peut donc la faire conditionnelle:
if il_la_faut == True :
from malibrairie import *
else:
pass # Ne fait rien, mais python est content !
•
•
•
•
import : l’inclut dans l’environnement d’exécution
mais tout est bien rangé: namespaces
pour l’utiliser il faut la qualifier: sys.path
Pour l’éviter il existe from
53
© 2009 Fernando NIÑO
Le programme principal
• Comme un script quelconque, il exécute au fur et à
mesure qu’il trouve des instructions:
–
–
–
–
import est une instruction
def aussi
s’il trouve des instructions, on y va !
mais, on peut savoir si un programme est principal ou
non:
if __name__ == ‘__main__’:
print “je suis un programme principal”
– cela s’utiliser pour tester des sous-programmes
54
© 2009 Fernando NIÑO
Ce qu’on retient
• Les habituels
–
–
–
–
–
for
if
while
break
continue
• L’organisation de l’espace de nommage
(namespaces):
– import
– module.fonction
55
© 2009 Fernando NIÑO
Formation Python
Python - Le Langage
Présentation
Travailler avec Python
Les bases du langage
Structures de données
Contrôle du flux d'exécution
Gestion des fichiers
Le Langage
Encapsulation
POO
Dérivation
Réutilisation
Gestion des erreurs
Exceptions
Logger
56
© 2009 Fernando NIÑO
Gestion des fichiers
• La base: l’objet fichier: fournit par open
f = open(‘toto’,’r’)
for line in f.readlines():
print line
f.close()
• Détail: les chemins: windows n’est pas *nix
import os.path
ici=os.path.realpath(os.curdir)
fich=os.path.join(ici,’nouveaufich.txt’)
if os.path.exists(fich) and os.path.isfile(fich):
print “Le fichier existe déjà”
57
© 2009 Fernando NIÑO
Expressions rationelles (regulières)
• Ce sont des “motifs” des recherche
• Un sujet à part entière... mais relativement simple
pour des choses simples:
m=re.match ("ab","cab") # Exact
m=re.search ("ab","cab") # Sous-ensemble
• Quantificateurs: . et .*
• Limites: ^, $
58
© 2009 Fernando NIÑO
Examples des regexp
'abcdefftp://toto.org/fich.zip/ghijklmnopq'
r1=’^.*ftp’
r2=’ftp.*$’
r3=’^.*$’
r4=’ftp.*?zip’
• Example: chercher la chaîne “ftp://xxxx.zip”
regex = re.compile('ftp://.*?\.zip')
for m in re.finditer(regex,line):
res=m.group()
# Non-greedy
59
© 2009 Fernando NIÑO
Exercice: Chercher “ftp://... .zip”
• Dans le fichier “modis” afficher toutes les
addresses de fichiers zip, en enlevant le “.zip”
• Aide: utiliser re.sub
60
© 2009 Fernando NIÑO
Solution: parsemessages.py
def main(argv=None):
if argv is None:
argv = sys.argv
if len(argv) != 2:
print help_message
nomf = argv[1]
f=open(nomf,'r')
regex = re.compile('ftp://.*?\.zip') # Non-greedy
zipre = re.compile('\.zip')
for line in f.readlines():
for m in re.finditer(regex,line):
res=m.group()
print re.sub(zipre,'/',res)
f.close()
61
© 2009 Fernando NIÑO
Exemple: lister des fichiers
• Lister l’arborescence de fichiers:
– implique accéder au listing au système de fichiers
– utilise la bibliothèque standard python
import fnmatch, os.path
– documentation
print fnmatch.__doc__
print os.path.walk.__doc__
– ou sur ipython
fnmatch?
os.path.walk ?
– ou encore pydoc
/usr/lib64/python2.3/pydoc.py -p 34567
62
© 2009 Fernando NIÑO
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple
(exListeRep.py)
import fnmatch, os
def find(pattern, startdir=os.curdir):
matches = []
os.path.walk(startdir, findvisitor, (matches,
pattern))
return matches
def findvisitor((matches, pattern), thisdir, nameshere):
for name in nameshere:
if fnmatch.fnmatch(name, pattern):
fullpath = os.path.join(thisdir, name)
matches.append(fullpath)
if __name__ == '__main__':
import sys
namepattern, startdir = sys.argv[1], sys.argv[2]
for name in find(namepattern, startdir):
print name
© 2009 Fernando NIÑO
63
Exemple (2)
•
•
•
•
sys.argv
os.path.join
os.path.walk
fnmatch.fnmatch
• Exercice:
– faire que le résultat affiche la taille du fichier (trouvez la
fonction à utiliser !) si un troisième arg. est taille
python exListeRep.py ‘.*rc’ ~ alpha
– ou
python exListeRep.py ‘.*rc’ ~ taille
64
© 2009 Fernando NIÑO
Solution (exListeRep2.py)
import fnmatch, os
if __name__ == '__main__':
from sys import argv
namepattern, startdir,trois = argv[1], argv[2],argv[3]
matches=find(namepattern, startdir)
if trois == 'alpha' :
for name in matches:
print name
elif trois == 'taille':
for name in matches:
print "%s : %d" % (name,os.path.getsize(name))
else:
print "Troisieme argument inconnu"
65
© 2009 Fernando NIÑO
Exercice
• La même chose, mais en faisant le tri par nom
if __name__ == '__main__':
from sys import argv
namepattern, startdir,trois = argv[1], argv
[2],argv[3]
matches=find(namepattern, startdir)
if trois == 'alpha' :
matches.sort()
for name in matches:
print name
elif trois == 'taille':
for name in matches:
print "%s : %d" % (name,os.path.getsize
(name))
else:
print "Troisieme argument inconnu"
66
© 2009 Fernando NIÑO
Exercice
• Idem, mais par taille
67
© 2009 Fernando NIÑO
Solution (exListeRep4.py)
• On crée une structure de données (nom, taille)
...
elif trois == 'taille':
fichiers=[]
for name in matches:
fichiers.append([name,os.path.getsize
(name)])
fichiers.sort(lambda x,y: -cmp(x[1],y[1]))
for nom in fichiers:
print "%s : %d" % (nom[0],nom[1])
68
© 2009 Fernando NIÑO
Gestion de fichiers
• On a vu comment parcourir une arborescence
• Ouverture, écriture et modification de fichiers ?
– syntaxe proche du C``
fichier=open(nomfichier,’r’)
listeTout=fichier.readlines()
fichier.close()
– avec ipython faites fichier.<TAB>
• Exercice: lisez votre fichier .bashrc en utilisant
readlines et affichez-le sur l’écran (pensez aux
lignes blanches...)
69
© 2009 Fernando NIÑO
Fichiers texte
• readlines() vs readline()
– est pratique mais consomme de la mémoire.
fichier=open('.bashrc','r')
for ligne in fichier.readlines():
print ligne
fichier.close()
– Pour un gros fichier, il vaut mieux lire ligne par ligne
fichier=open('.bashrc','r')
ligne = fichier.readline()
while ligne:
if ligne.endswith('\n'):
ligne=ligne[:-1]
print ligne
ligne = fichier.readline()
fichier.close()
70
© 2009 Fernando NIÑO
Iterateurs
• Le comportement de readline() vs readlines() est
typique de l’approche des itérateurs:
– au lieu de créer une liste en mémoire à parcourir, on créé
une fonction qui, à chaque appel, renvoie l’élément
suivant.
– range(10) : créé une liste de 0 à 9
– xrange(10) : créé un itérateur qui à chaque appel donne
l’élément suivant le dernier.
• Exercise : tester range et xrange avec ipython.
71
© 2009 Fernando NIÑO
Remplacement de texte
• Remplacer une chaîne par une autre dans un
fichier
import os, sys
nargs = len(sys.argv)
if not 3 <= nargs <= 5:
print "usage: %s search_text replace_text
[infile [outfile]]" % \
os.path.basename(sys.argv[0])
else:
<<la suite>>
72
© 2009 Fernando NIÑO
Remplacement de texte
• <<la suite >> (searchreplace.py)
stext = sys.argv[1]
rtext = sys.argv[2]
input_file = sys.stdin
output_file = sys.stdout
if nargs > 3:
input_file = open(sys.argv[3])
if nargs > 4:
output_file = open(sys.argv[4], 'w')
for s in input_file:
output_file.write(s.replace(stext, rtext))
if nargs > 4:
output_file.close()
input_file.close()
73
© 2009 Fernando NIÑO
Exercice
• Encapsulez la fonctionnalité searchreplace pour
qu’elle agisse sur un ensemble de fichiers d’un
repertoire:
searchreplacedir.py search_text replace_text
file_pattern startdir newfile_extension
74
© 2009 Fernando NIÑO
Solution (searchreplacedir.py)
def searchreplace(stext,rtext,inputname, outputname):
input_file = open(inputname)
output_file = open(outputname, 'w')
for s in input_file:
output_file.write(s.replace(stext, rtext))
output_file.close()
input_file.close()
if __name__ == '__main__':
nargs = len(sys.argv)
if nargs != 6:
print "usage: %s search_text replace_text file_pattern
startdir newfile_extension" % \
os.path.basename(sys.argv[0])
else:
stext, rtext, namepattern, startdir, newext = \
sys.argv[1], sys.argv[2],sys.argv[3], sys.argv[4],sys.argv[5]
for name in find(namepattern, startdir):
newname="%s.%s" % (name,newext)
print "Traitement de %s ==> %s" % (name,newname)
searchreplace(stext,rtext,name,newname)
75
© 2009 Fernando NIÑO
Solution (searchreplacedir.py)
def searchreplace(stext,rtext,inputname, outputname):
input_file = open(inputname)
output_file = open(outputname, 'w')
for s in input_file:
output_file.write(s.replace(stext, rtext))
output_file.close()
input_file.close()
if __name__ == '__main__':
nargs = len(sys.argv)
if nargs != 6:
print "usage: %s search_text replace_text file_pattern
startdir newfile_extension" % \
os.path.basename(sys.argv[0])
else:
stext, rtext, namepattern, startdir, newext = \
sys.argv[1], sys.argv[2],sys.argv[3], sys.argv[4],sys.argv[5]
for name in find(namepattern, startdir):
newname="%s.%s" % (name,newext)
print "Traitement de %s ==> %s" % (name,newname)
searchreplace(stext,rtext,name,newname)
75
© 2009 Fernando NIÑO
Solution (searchreplacedir.py)
def searchreplace(stext,rtext,inputname, outputname):
input_file = open(inputname)
output_file = open(outputname, 'w')
for s in input_file:
output_file.write(s.replace(stext, rtext))
output_file.close()
input_file.close()
if __name__ == '__main__':
nargs = len(sys.argv)
if nargs != 6:
print "usage: %s search_text replace_text file_pattern
startdir newfile_extension" % \
os.path.basename(sys.argv[0])
else:
stext, rtext, namepattern, startdir, newext = \
sys.argv[1], sys.argv[2],sys.argv[3], sys.argv[4],sys.argv[5]
for name in find(namepattern, startdir):
newname="%s.%s" % (name,newext)
print "Traitement de %s ==> %s" % (name,newname)
searchreplace(stext,rtext,name,newname)
75
© 2009 Fernando NIÑO
Solution (searchreplacedir.py)
def searchreplace(stext,rtext,inputname, outputname):
input_file = open(inputname)
output_file = open(outputname, 'w')
for s in input_file:
output_file.write(s.replace(stext, rtext))
output_file.close()
input_file.close()
if __name__ == '__main__':
nargs = len(sys.argv)
if nargs != 6:
print "usage: %s search_text replace_text file_pattern
startdir newfile_extension" % \
os.path.basename(sys.argv[0])
else:
stext, rtext, namepattern, startdir, newext = \
sys.argv[1], sys.argv[2],sys.argv[3], sys.argv[4],sys.argv[5]
for name in find(namepattern, startdir):
newname="%s.%s" % (name,newext)
print "Traitement de %s ==> %s" % (name,newname)
searchreplace(stext,rtext,name,newname)
75
© 2009 Fernando NIÑO
Solution (searchreplacedir.py)
def searchreplace(stext,rtext,inputname, outputname):
input_file = open(inputname)
output_file = open(outputname, 'w')
for s in input_file:
output_file.write(s.replace(stext, rtext))
output_file.close()
input_file.close()
if __name__ == '__main__':
nargs = len(sys.argv)
if nargs != 6:
print "usage: %s search_text replace_text file_pattern
startdir newfile_extension" % \
os.path.basename(sys.argv[0])
else:
stext, rtext, namepattern, startdir, newext = \
sys.argv[1], sys.argv[2],sys.argv[3], sys.argv[4],sys.argv[5]
for name in find(namepattern, startdir):
newname="%s.%s" % (name,newext)
print "Traitement de %s ==> %s" % (name,newname)
searchreplace(stext,rtext,name,newname)
75
© 2009 Fernando NIÑO
Solution (searchreplacedir.py)
def searchreplace(stext,rtext,inputname, outputname):
input_file = open(inputname)
output_file = open(outputname, 'w')
for s in input_file:
output_file.write(s.replace(stext, rtext))
output_file.close()
input_file.close()
if __name__ == '__main__':
nargs = len(sys.argv)
if nargs != 6:
print "usage: %s search_text replace_text file_pattern
startdir newfile_extension" % \
os.path.basename(sys.argv[0])
else:
stext, rtext, namepattern, startdir, newext = \
sys.argv[1], sys.argv[2],sys.argv[3], sys.argv[4],sys.argv[5]
for name in find(namepattern, startdir):
newname="%s.%s" % (name,newext)
print "Traitement de %s ==> %s" % (name,newname)
searchreplace(stext,rtext,name,newname)
75
© 2009 Fernando NIÑO
Solution (searchreplacedir.py)
def searchreplace(stext,rtext,inputname, outputname):
input_file = open(inputname)
output_file = open(outputname, 'w')
for s in input_file:
output_file.write(s.replace(stext, rtext))
output_file.close()
input_file.close()
if __name__ == '__main__':
nargs = len(sys.argv)
if nargs != 6:
print "usage: %s search_text replace_text file_pattern
startdir newfile_extension" % \
os.path.basename(sys.argv[0])
else:
stext, rtext, namepattern, startdir, newext = \
sys.argv[1], sys.argv[2],sys.argv[3], sys.argv[4],sys.argv[5]
for name in find(namepattern, startdir):
newname="%s.%s" % (name,newext)
print "Traitement de %s ==> %s" % (name,newname)
searchreplace(stext,rtext,name,newname)
75
© 2009 Fernando NIÑO
Jour 1 – Le langage
Formation Python
Python - Environnement
Communication avec
d'autres programmes
Environnement
Bonnes
Pratiques
76
© 2009 Fernando NIÑO
Communication inter-programmes
• L’approche la plus simple
os.system(“n’importe quelle commande”)
– exécutée dans un shell standard
– Exemple
import os
for i in range(0,500):
os.system("mkdir rep%d" % i)
• Dans tous les cas, il vaut mieux utiliser les
interfaces natives Python (tar, compression...)
import os
for i in range(0,500):
os.mkdir("rep%d" % i)
77
© 2009 Fernando NIÑO
Communication par pipes
• Utile quand un programme lit et l’autre écrit
import os
f = os.popen('gnuplot', 'w')
print >>f, "set yrange[-300:+300]"
for n in range(300):
print >>f, "plot %i*cos(x)+%i*log(x+10)" % (n,
150-n)
f.flush()
f.close()
78
© 2009 Fernando NIÑO
Communication par pipes (2)
• Pour lire une sortie standard (pas de stderr !)
listing = getCommandOutput2('ls -1 2>/dev/null')
• Une façon de lire le résultat
def getCommandOutput2(command):
child = os.popen(command)
data = child.read()
err = child.close()
if err:
raise RuntimeError, '%r failed with exit
code %d' % (command, err)
79
© 2009 Fernando NIÑO
Communication par pipes (3)
• Un peu long... voir getCommandOutput.py
• Utilisation
from getCommandOutput import *
output=getCommandOutput("ls")
print "Sortie = %s" % output
try:
output=getCommandOutput("ljs")
print "Sortie = %s" % output
except RuntimeError, error:
print str(error)
80
© 2009 Fernando NIÑO
Jour 1 – Le langage
Formation Python
Python - Environnement
Communication avec
d'autres programmes
Bonnes
Pratiques
Programmation dirigée par les tests
Documentation
LEO
Environnement
81
© 2009 Fernando NIÑO
Programmation dirigée par les tests
• L’avantage d’un langage dynamique est que l’on
peut tester au fur et à mesure : même la syntaxe
d’une seule ligne, sans avoir à compiler
• On peut donc raccourcir le cycle codage <-> test
pour déceler des erreurs le plus tôt possible.
Codage incremental.
• Donc... Tests Unitaires
• Et exécution des tests unitaires le plus souvent
possible (vérification de non-regression).
82
© 2009 Fernando NIÑO
Tests unitaires
• Cas simple: assertions
assert(mafonction(3.5) == 1)
• La face cachée:
if __debug__:
if not expression: raise AssertionError
• Optimisation desactive __debug__:
python -O
# à l’invocation
83
© 2009 Fernando NIÑO
Bonne pratique
• Utilisez des assertions quand c’est possible
• Créer des modules de la forme
import mod1, mod2..
class MaClasse:
def..
def...
if __name__ == ‘__main__’:
# Je commence des tests unitaires du module
mc=MaClasse()
assert(mc.fonction1(2.3) == 4)
liste=mc.fonction2(‘test’)
assert(len(liste) == 5)
84
© 2009 Fernando NIÑO
Bonne pratique
• Utilisation
python monmodule.py
– exécute les tests
import monmodule
mc = monmodule.MaClasse()
...
– ne les exécute pas
• Alternatives, meilleures plus sophistiquées
– UNITTEST
http://pyunit.sourceforge.net/ (livré en standard)
– DOCTEST (livré en standard aussi)
85
© 2009 Fernando NIÑO
Documentation
• Il y a une documentation automatique des modules
et des fonctions. Il suffit de la renseigner sous
forme d’un string après la définition du module ou
fonction:
class Base:
"""Celle-ci est la classe de base
et s’utilise comme il se doit
"""
pass
– accessible avec
Base.__doc__
• L’utilitaire pydoc s’utilise pour cela
pydoc -p 3456
86
© 2009 Fernando NIÑO
Programmation littéraire
• Inventé par D. Knuth à partir de son système TeX
et un compilateur Pascal (WEB system).
Aujourd’hui, CWEB (TeX/C) et NOWEB et d’autres
ont la même philosophie:
– Un programme doit être écrit pour les humains, non pour
une machine
– donc, l’explication du fonctionnement du programme doit
être le programme lui-même
• Le principe: une seule source, après traitement
génère
– la documentation (avec weave)
– le code compilable (avec tangle)
87
© 2009 Fernando NIÑO
Programmation littéraire (2)
• L’avantage de la méthode:
– le code et les commentaires sont toujours synchronisés
(si le mécanisme de génération de sources/compilation
est automatique..)
– En réfléchissant davantage, il y a moins de bogues.
• L’inconvenient
– c’est dur d’écrire des commentaires et encore plus de le
faire avec pertinence.
88
© 2009 Fernando NIÑO
Exemple noweb
% Copyright 1991 by Norman Ramsey. All rights reserved.
% See file COPYRIGHT for more information.
% l2h substitution nw <tt>noweb</tt>
% some insanity is needed to avoid getting a double square
bracket
% l2h substitution [ <b>[</b><b>[</b>
% l2h substitution ] <b>]</b><b>]</b>
\def\nw{{\tt noweb}}
\def\[{\ifhmode\ \fi$[\mkern-2mu[$}
\def\]{$]\mkern-2mu]$}
\title{Printing Primes: An example of \nw}
\section{Printing Primes: An example of \nw}
The following program is essentially the program that appears in
Reference~\cite{knuth:literate}, the first article on literate
programming,
but rendered using \nw.
An important differents is the {\tt WEB} has macros, but \nw\
does not.
89
© 2009 Fernando NIÑO
Example noweb (2)
\section{The output phase}
<<other constants of the program>>=
rr = 50;
cc = 4;
ww = 10;
<<variables of the program>>=
`page_number: integer;
`page_offset: integer;
`row_offset: integer;
c: 0..cc;
@
<<print table [[p]]>>=
begin page_number := 1; page_offset := 1;
while page_offset <= m do
begin <<output a page of answers>>;
page_number := page_number + 1;
page_offset := page_poffset + rr * cc;
end;
end
90
© 2009 Fernando NIÑO
LEO
• Bien que noweb, CWEB & compagnie soient très
intéressants, il est vrai qu’il est pas toujours facile
de suivre la documentation et le code au même
temps.
• Une alternative: Literate Programming Editor with
Outlines
– On organise de l’information comme on veut, en mode
“Plan”
– On génère du code à partir de là (comme avec WEB) et ce
de façon automatique (à chaque “save” on génère le code
associé).
– Résultat: le code est plus accessible, avec une granularité
variable (haut niveau, bas niveau).
91
© 2009 Fernando NIÑO
LEO
92
105
© 2009 Fernando NIÑO
Codage sous LEO
• Pas évident au départ
• Le codage se fait comme ceci:
def fonction(param1, param2):
<<initialisation fonction>>
for i in sequence:
<<traiter sequence>>
– où “initialisation fonction” et “traiter séquence” sont
définis par la suite (ou même avant) dans d’autres noeuds
LEO (puisque l’ensemble est un arbre)
• Mot-clé sur le ouèbe: edreamleo
93
© 2009 Fernando NIÑO