Programacion de computadora mediante PythonDescripción completa
Descripción completa
Full description
Mario Essert, Domagoj Ševerdija, Ivan Vazler Digitalni udžbenik Python - osnove - Odjel za matematiku Sveučilišta Josipa Jurja Strossmayera Osijek, 2007. Sadržaj Sadržaj 1 Python interpreter 1...
Copyright Copyright (c) 2003-2007 2003-2007, , Raphael Raphael MARVIE MARVIE l.fr> Permis Permissio sion n is grante granted d to copy, copy, distri distribut bute e and/or and/or modify modify this this docume document nt unde under r the the term terms s of the the GNU GNU Free Free Docu Docume ment ntat atio ion n Lice Licens nse, e, Vers Versio ion n 1.2 1.2 or any any late later r vers versio ion n publ publis ishe hed d by the the Free Free Soft Softwa ware re Foun Founda dati tion on; ; with with the the Inva Invari rian ant t Sect Sectio ions ns bein being g "Cha "Chapi pitr tre e 1, Prem Premie iers rs pas" pas", , "Ch "Chap apit itre re 2, Quelqu Quelques es module modules s et builtbuilt-in" in", , "Chapi "Chapitre tre 3, Plonge Plongeon on dans dans les objets objets", ", "Cha "Chapi pitr tre e 4, Pyth Python on et XML" XML", , "Cha "Chapi pitr tre e 5, Pyth Python on et la pers persis ista tanc nce e de donn´ ees" es", "Cha "Chap pitre itre 6, Pyth ython et les les int interf erfaces aces gra graphiq phiqu ues" es", the the Fron Frontt-Co Cove ver r Text Text bei being ng "In "Init itia iati tion on ` a Pyth Python on par par l’ex l’exem empl ple" e", , and and no Back Back-C -Cov over er Tex Texts ts. . A copy copy of of the the lice licens nse e is inc inclu lude ded d in the the sec secti tion on entitled entitled "GNU Free Documentat Documentation ion License". License".
c 2003-2007, 2003- 2007, Rapha¨el el Marvie
Avant-propos Ce support propose une initiation au langage Python par l’exemple. Il fait suite a` une formation formation d’une semaine et comportant comportant 6 cours. Cette version version essaye essaye de compl´ compl´eter eter les transparents, mais ne regroupe malheureusement pas tout le discours accompagnant la pr´esentation esentation des transparents. La formation se faisant en salle machine, tous les exemples ´etaient etaie nt test´ t est´es es interactivement intera ctivement pendant pen dant le cours. cour s. Cette Cett e approche appro che est volontairement volontair ement conserv´ conse rv´ee ee ici et il est conseill´e d’utiliser ce support avec un interpr´eteur eteur lanc´e pour voir ce qui se passe . Ce support de cours est destin´ destin´e a` un public ´etant etant familier avec avec au moins un langage de programmation, programmation, si possible orient´ orient´e objet, et ˆetre etre familier familier avec avec les notions d’objet. Ce support n’est pas un cours de programmation, ni un cours complet sur le langage Python, il ne repr´esente esente qu’une initiation a` diff´ diff´erentes erentes choses choses que l’on peut faire avec Python. La version utilis´ ut ilis´ee ee dans ce support est la 2.4.1. Les premiers compl´ements ements de ce support sont les documents associ´es es au langage Python comme la librairie librairie standard [7] le manuel manuel de r´ef´ ef´erence eren ce [8] ou bien le tutoriel tutor iel officiel officie l [9]. Sans ambition d’ˆetre etre suffisant, la mise en ligne de ce support a pour unique objectif ob jectif d’ˆetre etre ´eventuellement eventuellement utile. u tile. Le format retenu permet une impression en deux par page . Toute remarque concernant ce support est toujours la bienven bienvenue ue ! ( (
Introduction Un peu d’histoire Python est un langage de programmation objet interpr´et´e. Son origine est le langage de script du syst`eme d’exploitation Amoeba (1990). Il a ´et´e d´evelopp´e par Guido Von Rossum au CWI, a` l’Universit´ e d’Amsterdam et nomm´e par rapport au Monthy Python’s Flying Circus. Depuis, Python est devenu un langage de programmation g´en´eraliste (comp.lang.python est cr´e´e en 1994). Il offre un environnement complet de d´eveloppement comprenant un interpr´eteur performant et de nombreux modules. Un atout ind´eniable est sa disponibilit´e sur la grande ma jorit´e des plates-formes courantes (BeOS, Mac OS X, Unix, Windows). Python est un langage open source support´e, d´evelopp´e et utilis´e par une large communaut´e : 300, 000 utilisateurs et plus de 500, 000 downloads par an.
Python, ` a quoi bon ? Pour r´esumer Python en quatre points forts.
Qualit´e L’utilisation de Python permet de produire facilement du code ´evolutif et maintenable et offre les avantages de la programmation orient´ee-objet. Productivit´e Python permet de produire rapidement du code compr´ehensible en rel´eguant nombre de d´etails au niveau de l’interpr´eteur. Portabilit´ e La disponibilit´e de l’interpr´eteur sur de nombreuses plates-formes permet l’ex´ecution du mˆeme code sur un PDA ou un gros syst`eme1 . Int´ egration L’utilisation de Python est parfaitement adapt´ee l’int´egration de composants ´ecrit dans un autre langage de programmation (C, C++, Java avec Jython). Embarquer un interpr´eteur dans une application permet l’int´ egration de scripts Python au sein de programmes. Quelques caract´ eristiques int´ eressantes – langage interpr´et´e (pas de phase de compilation explicite) – pas de d´eclarations de types (d´eclaration a` l’affectation) – gestion automatique de la m´emoire (comptage de r´ef´erences) 1
Mˆ eme si un tel cas semblerait un peu bizarre.
9
` TABLE DES MATIERES
10
– programmation orient´e ob jet, proc´edural et fonctionnel – par nature dynamique et interactif – possibilit´e de g´en´erer du byte-code (am´eliore les performances par rapport a` une interpr´etation perpetuelle) – interactions standards (appels syst`emes, protocoles, etc.) – int´ egrations avec les langages C et C++
Python ou pas Python ? Comme tout langage de programmation Python n’est pas la solution ultime a` tous les besoins. Toutefois, on retrouve son utilisation dans diff´erents contextes [4] comme Google, la NASA, YouTube, Industrial Light & Magic, le projet One Laptop Per Child , l’environnement Opie sur pocket PC, etc. Python est donc adapt´e pour r´ealiser de grosses applications . ( (
) )
Quand Python ? Python est un tr`es bon langage pour le d´eveloppement agile [1] et it´eratif. Il permet d’ˆetre r´eactif et ´evite le cycle lourd programmer / compiler / tester. De plus, le langage permet de v´erifier tr`es rapidement des hypoth`eses de mise en œuvre. Une fois la solution r´ealis´ee en Python, il est alors toujours possible de l’optimiser davantage en red´eveloppant certain de ses composants en C++ par exemple. Python permet de produire des applications facilement extensibles non seulement par le d´eveloppeur mais aussi dans certains cas par l’usager (de nombreuses librairies scientifiques sont disponibles). Enfin, Python est un bon candidat pour l’automatisation de tˆ aches syst`emes. Le syst`eme d’administration de la distribution Gentoo Linux portage est d´evelopp´e en Python. Une partie au moins du support de l’int´egration continue chez Google est fait en Python. Quand pas python ? Dynamicit´e est rarement compatible avec haute performance, Python n’est donc certainement pas le meilleur langage pour faire du traitement intensif. Dans certain cas, les usagers pr´ef`erent limiter l’utilisation de Python a` l’aspect int´egration de composants afin de produire des syst`emes performants. La version Python fournit une preuve de concept ou une version fonctionnelle avant de red´evelopper les points faibles. Toutefois, les performances de Python sont souvent suffisante pour des applications a` forte charge (cf. YouTube) Une certitude pour terminer, Python permet d’identifier rapidement une mauvaise id´ee...
c 2003-2007, Rapha¨el Marvie
Chapitre 1 Premiers pas 1.1
Utilisation de Python
Python, comme la majorit´e des langages dit de script, peut ˆetre utilis´e aussi bien en mode interactif qu’en mode script / programme. Dans le premier cas, il y a un dialogue entre l’utilisateur et l’interpr´ eteur : les commandes entr´ees par l’utilisateur sont ´evalu´ees au fur et a` mesure. Cette premi`ere solution est pratique pour le prototypage, ainsi que pour tester tout ou partie d’un programme ou plus simplement pour interagir ais´ement et rapidement avec des structures de donn´ees complexes. Le listing suivant pr´esente comment lancer l’interpr´eteur (simplement en tapant python `a l’invite du shell1 ) et comment en sortir (en tapant Ctrl-D). $ p yt ho n P yt ho n 2 .4 .3 ( # 1, Apr 7 2006 , 1 0: 54 :3 3) [ G CC 4 .0 .1 ( A pp le C om pu te r , I nc . b ui ld 5 25 0) ] o n d ar wi n T yp e " h el p " , " c o py r ig h t " , " c r ed it s " o r " l i ce n se " f or m or e i n fo r ma t io n . > >> p ri nt ’ h el lo w or ld ! ’ h e ll o w o rl d ! > >> ^ D $
Pour une utilisation en mode script les instructions a` ´evaluer par l’interpr´eteur sont sauvegard´ ees, comme n’importe quel programme informatique, dans un fichier. Dans ce second cas, l’utilisateur doit saisir l’int´egralit´e des instructions qu’il souhaite voir ´evaluer `a l’aide de son ´editeur de texte favori, puis demander leur ex´ecution a` l’interpr´eteur. Les fichiers Python sont identifi´es par l’extension .py. Le listing suivant, l’interpr´eteur est appel´e avec en param`etre le nom du programme a` ´evaluer (le traditionnel ‘hello world’). Dans le cas d’un syst`eme Unix, la premi`ere ligne du fichier hello.py pr´ecise quel interpr´eteur utiliser pour ´evaluer le fichier si ce dernier est ex´ecutable. Il suffit dans ce cas de taper le nom du fichier a` l’invite du shell. $ c at h el lo . p y 1
Dans tout ce support l’invite du shell sera identifi´ e par la lettre $.
11
12
Premiers pas
# ! / u s r / b in / e n v p y th o n p r in t ’ h e ll o w o rl d ! ’ $ p yt ho n h el lo . p y h e ll o w o rl d !
1.2 1.2.1
Structures de base Commentaires
Comme dans la majorit´e des langages de script, les commentaires Python sont d´efinis `a l’aide du caract`ere #. Qu’il soit utilis´e comme premier caract`ere ou non, le # introduit un commentaire jusqu’`a la fin de la ligne. Comme toujours, les commentaires sont a` utiliser abondamment avec parcimonie. Il ne faut pas h´esiter a` commenter le code, sans pour autant mettre des commentaires qui n’apportent rien. Le listing suivant pr´esente une ligne de commentaire en Python. Les commentaires seront de nouveaux abord´es en 1.3.5 pour l’auto-documentation. Les commentaires introduits par # devraient ˆetre r´eserv´es au remarques sur le code en sa mise en œuvre. >>> # c ec i e st u n c o mm e nt a ir e > >> p ri nt ’ b ou h ’ # c ec i e st a us si u n c o mm e nt a ir e bouh
1.2.2
Typage en Python
En Python, tout est objet. Quelque soit les donn´ ees que l’on manipule, ces donn´ ees sont des objets dont les classes sont d´efinies par l’usager, ou par l’environnement Python pour les types de base. Une cons´ equence est que l’utilisateur manipule les donn´ ees au travers de r´ef´erences (qui donnent acc`es aux fonctionnalit´es des instances). Cette approche permet de rendre homog`ene les donn´ees manipul´ees par l’utilisateur (comme c’´etait le cas en SmallTalk). Ainsi, toutes les donn´ees suivantes suivant sont des objets : 1, [2, 3, 4], 5.6, ’toto’, une instance de Foo. Python est un langage a` typage dynamique. Ceci ne veut pas dire que les donn´ees que l’on manipule ne sont pas typ´ees, mais que leur type est calcul´e lors de leur utilisation2 . Dans ce contexte, le type des variables n’est pas d´efini explicitement par l’utilisateur. Ainsi, une mˆeme variable peut r´ef´erencer dans un programme des objets de types diff´erents3 . ( (
) )
>>> x = 1 # x r ef er en ce un e nt ie r > >> x = ’ toto ’ # x r ef e re n ce d e so rm a is u ne c ha in e > >> x = Foo () # x r ef e re n ce d e so rm a is u ne i ns ta nc e d e F oo 2
En Python, ce calcul se r´esume `a la possibilit´e pour l’ob jet de recevoir un message particulier. Il est toutefois a` noter que cette facilit´e ne devrait ˆetre utilis´ees que sous couvert du polymorphisme, sans quoi la lisibilit´e du programme s’en trouve r´eduite. 3
c 2003-2007, Rapha¨el Marvie
1.2 Structures de base
1.2.3
13
Arithm´ etique
Python permet d’exprimer tr`es simplement des op´erations arithm´etiques. Dans le cas o`u tous les op´erandes sont des entiers, alors les r´esultats seront aussi des entiers. Lorsqu’au moins un des op´erandes est de type r´eel, alors tous les op´erandes sont automatiquement convertis en r´eels. La colonne de droite du listing suivant pr´esente des op´erations ´el´ementaires sur des entiers, la colonne de droite sur des r´eels. >>> x >>> y >>> y 3 >>> y 2 >>> y > >> y 11.0 >>> x > >> x 4.0
= 1 + 2 = 5 * 2 / x % x = 5.5 * 2
= 12.0 / 3
Dans le contexte de l’arithm´etique, les affections peuvent prendre deux formes. Ces deux formes ont un sens diff´erent. Le listing suivant pr´esente deux affectations qui pourraient ˆetre comprises de mani`ere identique. Toutefois, la premi`ere forme (ligne 2) a pour cons´equence de cr´eer une nouvelle instance d’entier pour contenir l’ajout de 2 a` la valeur de x. La seconde forme (ligne 3) ajoute 2 a` la valeur de x sans cr´eer de nouvelle instance. La mani`ere d’´ecrire une op´eration a donc un impact sur son ´evaluation. >>> x = 4 >>> x = x + 2 >>> x += 2
1.2.4
Chaˆınes de caract` eres
Les chaˆınes de caract`eres se d´efinissent de plusieurs mani`eres en Python. Il est possible d’utiliser indiff´eremment des guillemets simples ou des guillemets doubles. Le choix est souvent impos´e par le contenu de la chaˆıne : une chaˆıne contenant des guillemets simples sera d´eclar´ee avec des guillemets doubles et r´eciproquement. Pour les autres cas, c’est indiff´erent. Enfin, comme tout est objet en Python une chaˆıne est donc un objet. Le listing suivant d´eclarer deux chaˆınes r´ef´erenc´ees par x et y. Enfin, la chaˆıne r´ef´erenc´ee par z est une chaˆıne de caract`eres multiligne (utilisation de trois quotes / guillemets simples ou doubles). >>> x = ’ hello ’ > >> y = " w or ld ! " > >> z = ’ ’’ he ll o world’’’
c 2003-2007, Rapha¨el Marvie
14 1.2.4.1
Premiers pas Concat´enation
La concat´enation de ces chaˆınes de caract`eres peut prendre deux formes. Dans les deux cas, l’op´erateur + est utilis´e pour exprimer la concat´ enation. La forme de droite est un raccourci d’´ecriture. >>> x = x + y >>> x ’ hello world ! ’
1.2.4.2
>>> x += y >>> x ’ hello world ! ’
Affichage
L’affichage de chaˆınes de caract`eres a` l’aide de la fonction print peut se faire en concat´enant explicitement des chaˆınes (que ce soit avec l’op´erateur de concat´enation ou en utilisant des virgules) ou en utilisant une chaˆıne de formatage comme la fonction printf du langage C. Cette seconde option est un peu plus puissante, mais aussi un peu plus lourde `a utiliser. Le listing suivant pr´esente trois mani`ere d’afficher des chaˆıne de caract`eres. >>> print ’I I s ay : h el lo > >> p ri nt x , h el lo w or ld ! > >> p ri nt " I I s ay : h el lo
1.2.4.3
say : ’ + x w or ld ! 2 , ’ ti me s ’ 2 t im es say : % s % d ti me ( s) " % ( x, 2) w or ld ! 2 t im e (s )
Manipulations
Python offre une m´ethode simple pour acc´eder aux caract`eres contenus dans une chaˆıne : une chaˆıne est manipul´ee comme une s´equence index´ee de caract`eres. Ainsi, chaque caract`ere est accessible directement par son index (le premier ´etant index´e 0) en utilisation des crochets. En plus de cet acc`es unitaire aux caract`eres, il est possible d’acc´eder a` des sous-chaˆınes en pr´ecisant la tranche souhait´ee l’index de d´ebut (qui est inclu) ´etant s´epar´e de l’index de fin (qui est exclu) par le caract`ere ‘ :’. Dans le cas des sous-chaˆınes, la valeur fournie est une copie et non un acc`es a` une partie de la chaˆıne d’origine. Le listing suivant donne quelques exemples d’acc`es a` un caract`ere (ligne 2), ou a` une sous-chaˆıne pour le reste. La colonne de gauche pr´esente des acc`es a` partir du d´ebut de la chaˆınes (les index sont positifs). La ligne 6 signifie que l’on souhaite le contenu de x du quatri`eme caract`ere a` la fin. La colonne de droite pr´esente des exemples de manipulation o`u certains index sont donn´es `a partir de la fin de la chaˆıne (ils sont n´egatifs). Enfin, la derni`ere ligne r´ealise une copie de la chaˆıne x. > >> x = ’ he ll o w or ld ! ’ > >> x [ 4] ’o ’ >>> x [2:4] ’ ll ’
>>> x [ -3:] ’ ld ! ’
c 2003-2007, Rapha¨el Marvie
1.2 Structures de base >>> x [3:] ’ lo world ! ’ > >> x [ :] ’ h e ll o w o rl d ! ’
1.2.5
15 >>> x [1: -1] ’ ello world ’
Listes
Les listes Python sont des ensemble ordonn´es et dynamique d’´el´ements. Ces ensemble peuvent contenir des ´el´ements de diff´erents types, leur seul point commun est que ce sont des ob jets. Et comme tout est ob jet, les listes sont elles mˆemes des objets (instances de la classe list). L’exemple suivant cr´ee tout d’abord une variable contenant la valeur vrai, puis une liste nomm´ee foo contenant la chaˆıne ’bar’, l’entier 12345 et le contenu de la variable x. >>> x = True > >> f oo = [ ’ ba r ’, 1 23 45 , x ]
L’ajout d’´el´ements dans une liste se fait a` l’aide des m´ethodes append pour un ajout en fin de liste, et insert, pour un ajout `a un index donn´e. Enfin, la m´ethode extend ajoute le contenu d’une liste pass´e en param`etre a` la fin de la liste. > > > f oo . a p p e nd ( ’ n e w ’ ) > >> f oo [ ’ ba r ’ , 1 23 45 , 1 , ’ n ew ’ ] > > > f oo . i n s e rt ( 2 , ’ n ew ’ ) > >> f oo [ ’ ba r ’ , 1 23 45 , ’ ne w ’ , 1 , ’ n ew ’ ] > > > f oo . e x t e nd ( [ 67 , 8 9 ]) > >> f oo [ ’ ba r ’, 1 234 5 , ’ ne w ’, 1 , ’ ne w ’, 67 , 8 9]
La m´ethode index permet de connaˆıtre l’index de la premi`ere occurrence d’un ´el´ement dans une liste. Dans le cas o`u l’´el´ement fournit en param`etre n’est pas pr´esent, la m´ethode l`eve l’exception ValueError. L’utilisation de la construction in retourne quant a` elle True si l’´el´ement est pr´esent dans la liste et False sinon. > > > f oo . i n d ex ( ’ n e w ’ ) 2 > > > f oo . i n d ex ( 3 4 ) T r ac eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 1 , in ? V a lu e Er r or : l is t . i nd ex ( x ): x n ot i n l is t > >> 34 in foo False
Les listes et les chaˆınes ont pour point commun le fait d’ˆetre des ensembles ordonn´es. L’acc`es `a un ´el´ement d’une liste se fait donc aussi par indexation (ligne 1). Il est possible de c 2003-2007, Rapha¨el Marvie
16
Premiers pas
prendre une partie de liste (ligne 3) et d’obtenir une copie de liste (ligne 5). Cette derni`ere manipulation est tr`es importante lors de parcours de listes (voir section 1.4.4) pour ne pas modifier la liste qui est parcourue. > > > f oo [ 2 ] ’new’ > > > f oo [ 1 : - 3 ] [ 12 34 5 , ’ n ew ’ , 1 ] > >> b ar = f oo [ :] > > > b ar . a p p e nd ( 3 ) > > > f oo [ - 1: ] [89] > > > b ar [ - 1 ] 3
Les listes peuvent ˆetre fusionn´ees par concat´enation. Ces concat´enations peuvent aussi se faire par copie ou par a jout. La ligne 1 repr´esente une concat´enation par copie des deux listes existantes. La ligne 4 pr´esente est une copie par concat´enation d’´el´ements a` une liste existante. Enfin, la ligne 7 pr´esente une mani`ere simple de cr´eer une liste par r´ep´etition d’un motif (qui est une sous liste). >>> > >> [0 , > >> > >> [0 , >>> [0 ,
bar = [0 , 1] + [1 , 0] b ar 1 , 1 , 0] bar += [2 , 3] b ar 1 , 1 , 0 , 2 , 3] [0 , 1] * 3 1 , 0 , 1 , 0 , 1]
De mani`ere sym´etrique `a l’a jout d’´el´ements dans une liste, il est possible d’en supprimer. La m´ethode remove permet de supprimer la premi`ere occurrence d’un ´el´ement d’une liste en le d´esignant (ligne 1). Si l’´el´ement fourni en param`etre n’existe pas dans la liste, l’exception etruire tout objet ValueError est lev´ee (ligne 4). L’op´erateur del (delete ) permet de d´ Python, y compris une sous liste (ligne 8). > > > f oo . r e m o ve ( ’ n e w ’ ) > >> f oo [ ’ ba r ’, 1 234 5 , 1 , ’ ne w ’, 67 , 8 9] > > > f oo . r e m o ve ( 3 4 ) T r ac eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 1 , in ? V a lu e Er r or : l is t . r em ov e ( x ): x n ot i n l is t > > > d e l f oo [ 1 : 3] > >> f oo [ ’ ba r ’ , ’ n ew ’ , 6 7 , 8 9]
D’autres formes plus avanc´ees de manipulation de listes sont pr´esent´ees dans la section 1.4.2. c 2003-2007, Rapha¨el Marvie
1.2 Structures de base
1.2.6
17
Listes et chaˆınes de caract` eres
Les listes et les chaˆınes de caract`eres sont similaire dans leur structure et dans leur manipulation. Certaines m´ethodes disponibles sur les chaˆınes manipulent les deux structures de donn´ees. La m´ethode join disponible sur les chaˆıne permet de construire une chaˆıne de caract`ere depuis une liste de chaˆınes. La chaˆıne sur laquelle est invoqu´ee la m´ethode join est alors utilis´e comme s´eparateur des diff´erents ´el´ements de la liste. > >> ’ ; ’ . jo in ( [ ’a ’ , ’ b ’, ’ c’ ]) ’a ; b ; c ’
De mani`ere sym´etrique, la m´ethode split, disponible sur les chaˆınes, permet de d´ecomposer une chaˆıne de caract`eres en une liste de sous chaˆınes. Ce d´ecoupage se fait par rapport `a un ou plusieurs caract`eres (ligne 1). Dans le cas o` u un entier est pass´e comme second argument, il pr´ecise le nombre maximum de d´ecoupage. > >> ’ h el lo c ra zy w or ld ! ’ . s pl it ( " " ) [ ’ h e ll o ’ , ’ c ra zy , ’ w o rl d ’ ] > >> ’ h el lo c ra zy w or ld ! ’ . s pl it ( " " , 1 ) [ ’ h e ll o ’ , ’ c r az y w o rl d ! ’ ]
1.2.7
Tuples
Les tuples sont des ensemble ordonn´es et immuables d’´el´ements. Comme les listes, les tuples peuvent contenir des donn´ees de diff´erents types. La ligne 1 pr´esente une d´eclaration classique (avec des parenth`eses) alors que la ligne 2 pr´esente la notation abr´eg´ee. La virgule est importante pour pr´eciser que l’on parle d’un tuple a` un ´el´ement et non de la valeur 12. Cette remarque serait valable dans la cas d’une d´eclaration parenth´es´ee d’un tuple a` un ´el´ement. > >> f oo = ( ’ ba r ’, 1 23 45 , x ) > >> bar = 12 ,
Comme les listes, les tuples sont accessibles par indexation (ligne 1 et 3), et la construction in permet de tester l’existance (ligne 5). Cependant, une fois cr´e´e le contenu d’un tuple ne peut ˆetre modifi´e. > > > f oo [ 1 ] 12345 > > > f oo [ : - 1 ] ( ’ b ar ’ , 1 2 34 5 ) > >> ’ ba r ’ in f oo True
Remarque Crit`eres de choix entre une liste et un tuple : – les tuples sont plus rapides `a parcourir que les listes, c 2003-2007, Rapha¨el Marvie
18
Premiers pas
– pour d´efinir des constantes, utiliser des tuples. Il est possible de convertir des tuples vers des listes (ligne 1) et r´eciproquement (ligne 3). > >> [1 , > >> > >> (1 ,
l is t (( 1 , 2 , 3 )) 2 , 3] f oo = t up le ( [1 , 2 , 3 ]) f oo 2 , 3)
Pour terminer, Python offre l’affectation multiple pour assigner diff´erentes valeurs depuis un tuples (ligne 1) de mani`re simultan´ee. Ici encore, les parenth`eses peuvent ˆetre omises (ligne 4). >>> > >> 1 >>> > >> 2
(x , y , z ) = foo x a, b, c = foo b
1.2.8
Dictionnaires
Les dictionnaires, parfois appel´es tableaux associatifs, sont des ensembles non ordonn´es d’´el´ements index´es par des cl´es. Une cl´e doit obligatoirement ˆetre immuable (chaˆıne, entier ou tuple). D’autre part, une cl´e est toujours unique. Un dictionnaire vide est d´eclar´e par deux accolades (ligne 1). L’ajout (ligne 2 et 3) et l’acc`es (ligne 6) aux ´el´ ements d’un dictionnaire se fait par indexation sur la cl´e associ´e a` l’´el´ement. L’affichage d’un dictionnaire (ligne 5) pr´esente une liste de paires cl´e : valeur . ( (
) )
> >> m yd ic t = { } > >> m yd ic t [ ’ fo o ’] = 4 56 > >> m yd ic t [ 12 3] = ’ b ar ’ > > > m y di c t { 12 3: ’ ba r ’ , ’ f oo ’ : 4 56 } > > > m y di c t [ 1 23 ] ’bar’
Les dictionnaires offrent des m´ethodes pour manipuler les cl´es. La m´ethode keys retourne une liste de toutes les cl´es du dictionnaire (ligne 1) et la m´ethode has_key retourne True so la cl´e donn´e en param`etre est pr´esente dans le dictionnaire et False dans le cas contraire. > > > m y di c t . k ey s ( ) [ 12 3 , ’ f oo ’ ] > > > m y di c t . h a s_ k ey ( ’ b a r ’ ) False
c 2003-2007, Rapha¨el Marvie
1.2 Structures de base
19
La m´ethode values donne acc`es a` une liste des valeurs contenues dans le dictionnaire (ligne 1) et la m´ethode items donne une liste de tuples, contenant chacun une paire cl´ e, valeur (ligne 3).. > > > m y di c t . v a lu e s ( ) [ ’ b ar ’ , 4 5 6] > > > m y di c t . i t em s ( ) [ (1 23 , ’ b ar ’ ) , ( ’ f oo ’ , 4 56 )]
La modification d’une valeur associ´ ee a` une cl´e se fait simplement en affectant de nouveaux la valeur index´ee dans le dictionnaire par la cl´e en question (ligne 1). Enfin, l’op´erateur del permet de supprimer une association association du dictionnaire (ligne 4). > >> m yd ic t [ 12 3] = 7 89 > > > m y di c t { 12 3: 7 89 , ’ f oo ’ : 4 56 } > > > d el m y di c t [ ’ f oo ’ ] > > > m y di c t { 1 23 : 7 8 9}
A l’aides des m´ethodes de manipulation des cl´e et des valeurs, il est possible de parcourir un dictionnaire de plusieurs mani`eres. Les quelques lignes suivantes donnent deux exemples de parcours. > >> f la me s = { ’ w in do ws ’ : ’ b of ’ , ’ u ni x ’ : ’ c oo l ’ } > >> f or k ey i n f la me s . k ey s ( ): ... print key , ’ is ’, flames [key ] ... w in do ws i s b of u ni x i s c oo l > >> f or k ey , v al ue i n f la me s . i te ms ( ) : ... print key , ’ is ’, value ... w in do ws i s b of u ni x i s c oo l
Ce dernier exemple pr´esente un parcours de dictionnaire avec une utilisation d’un list mapping et d’une chaˆıne de formatage (dont l’utilisation ne se limite pas a` l’affichage). > >> b ar = { ’a ’: ’ aa ’ , ’ b’ : ’ bb ’ , ’ c’ : ’ cc ’ } > >> [ "% s =% s " % ( x, y ) f or x , y in ba r . it em s ()] [ ’ a = aa ’ , ’ c = cc ’ , ’ b = bb ’ ]
c 2003-2007, Rapha¨el Marvie
20
Premiers pas
1.3 1.3.1
Constructions Structuration et indentation
La structuration d’un programme Python est d´efinie par son indentation. Le d´ebut d’un bloc est d´efini par un ’ :’, la premi`ere ligne pouvant ˆetre consid´er´ee comme un en-tˆete (test, boucle, d´efinition, etc.). Le corps du bloc est alors indent´e de mani`ere plus importante (mais r´eguli`ere) que l’en-tˆete. Enfin, la fin du bloc est d´elimit´e par le retour a` l’indentation de l’en-tˆete. Les bloc peuvent ˆetre imbriqu´es :
Dans le cas de bloc de taille r´eduite, par exemple une seule instruction, un bloc peut ˆetre d´efini sur une seule ligne. Le caract`ere ‘ :’ sert toujours de d´elimiteur entre l’en-tˆete et le corps. Les instructions du corps sont alors s´epar´ es par des ‘ ;’4 . Cependant, cette utilisation n’est pas n´ecessairement b´en´efique quant a` la lisibilit´ e du code, elle est donc a` 5 ´eviter . > > > < e n - t e te > : < i n s t r uc t i o n > ; < i n s t r uc t i o n >
Cette structuration est utilis´ee aussi bien pour d´efinir des boucles, des tests, des fonctions, des classes ou des m´ethodes.
1.3.2
Tests
Conditions bool´ eennes En Python, tout ce qui n’est pas faux est vrai. Les conditions bool´eennes fausses se r´esument au donn´ees vide : False, 0, "", [], {}, (), None. Python offre une seule construction pour r´ealiser des tests : le if then else. Une particularit´e de cette mise en œuvre est la possibilit´e d’enchaˆıner les tests avec la construction elif. ( (
) )
if x == ’ he ll o ’: p ri nt ’ h el lo t oo ! ’ e li f x = = ’ b on jo ur ’ : p r in t ’ b o n jo u r a u ss i ! ’ else: p ri nt ’ m oi p as c o mp r en d re ’
Les comparaisons entre s´equences (chaˆınes de caract`eres, listes et tuples) se fait selon l’ordre lexicographique. Les deux tests suivants sont vrais. (1 , 2 , 3) < (1 , 2 , 4) (1 , 2 , 3) < (1 , 2 , 3 , 4) 4
L’utilisation des ‘ ;’ en Python est optionnelle en fin de ligne et peut toujours ˆetre utilis´ee pour s´eparer deux instructions sur une mˆeme ligne. 5 L’´epoque o`u les caract`eres ´etaient compt´es dans une fichier est bien r´evolue.
c 2003-2007, Rapha¨el Marvie
1.3 Constructions
1.3.3
21
Boucles
Deux types de boucles sont disponibles : les boucles ´enum´er´ees (for) et les boucles bas´ ees sur un test de fin (while). Ces deux constructions suivent le mˆeme sch´ ema : un en-tˆete qui d´ecrit l’´evolution de la boucle, un ensemble d’instructions qui sont ´evalu´ees a` chaque tour de boucle et une partie optionnel qui est ´evalu´ee en sortie de boucle (introduite par le mot-cl´e else). Enfin, comme en C les boucles peuvent contenir les branchements continue pour passer a` l’it´eration suivante et break pour sortir de la boucle (dans ce cas la clause else n’est pas ´evalu´ee).
1.3.3.1
Boucles for
Une boucle for d´efinit une variable qui prend successivement toutes les valeurs de la s´equence (liste ou tuple) parcourue (ligne 1). La clause else est ´evalu´e lorsque la s´equence est ´epuis´ee et s’il n’y a pas eu de break (ligne 3). f or < v ar > i n < s e qu e nc e > : else: < i n s tr u ct i on s , s e qu e n ce e p ui s ee s a ns b re ak >
La fonction range produit une liste de tous les entiers entre une borne inf´erieur et une borne sup´erieur. Cette construction est utile lorsqu’une boucle for repose sur l’utilisation d’une s´equence d’entiers. La fonction range est utilisable de trois mani`eres : – un seul param`etre sp´ecifiant le nombre d’´el´ements (ligne 1), – deux param`etres sp´ecifiant la borne inf´erieure (inclue) et sup´erieure (exclue) (ligne 3), – trois param`etres sp´ecifiant les bornes et le saut (incr´ement entre deux ´el´ements de la s´equence) (ligne 5). >>> [0 , > >> [3 , > >> [0 ,
r a ng e ( 6 ) 1 , 2 , 3 , 4 , 5] r an ge ( 3 , 7 ) 4 , 5 , 6] r an ge ( 0 , 1 0, 3 ) 3 , 6 , 9]
Boucle for parcourant une s´equence de chaˆıne (ligne 2-3) et parcourant une liste de valeurs (ligne 7-8) pour acc´eder aux ´el´ements d’une liste. S’il est n´ecessaire de parcourir une s´equence tout en connaissant l’index de l’´el´ement courant, la fonction enumerate est une solution plus pythonesque (ligne 11-12). ( (
) )
> >> a = [ ’ he ll o ’, ’ wo rl d ’] > >> for elt in a : ... print elt ... hello world
c 2003-2007, Rapha¨el Marvie
22
Premiers pas
> >> f or ... ... 0 h el lo 1 w or ld > >> f or ... ... 0 h el lo 1 w or ld
1.3.3.2
i dx i n r an ge ( l en ( a ) ): print idx , a [ idx ]
i dx , v al i n e n um e ra te ( a ) : print idx , val
Boucles while
Une boucle while d´efinit une condition bool´eenne avec les mˆeme r`egles que pour les tests (ligne 1). Tant que cette condition est respect´ ee, les instruction du bloc associ´ e au e losrque la condition est fausse et qu’il n’y while sont ´evalu´ees. La clause else est ´evalu´ a pas eu de break (ligne 3). while : else: < i n s t r u ct i o n s , c o n d i t i on f a us s e >
La boucle suivante repr´esente la boucle minimale d´efinissable avec un while. Certes, elle est stupide mais elle permet d’illustrer l’utilisation du Ctrl-C pour interrompre un traitement en cours d’ex´ecution. > >> w hi le 1 : ... pass ... T r ac eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 1 , in ? KeyboardInterrupt
1.3.4
Fonctions
Il n’y a que des fonctions en Python. Une fonction est d´efinie avec le mot cl´e def. Une fonction retourne toujours une valeur. Si une fonction ne contient pas de clause return, la valeur None est alors retourn´ee6 . > >> d ef f ib ( n ): # s ui te d e f ib on ac ci j us qu e n ... a, b = 0, 1 ... while b < n : ... print b , ... a, b = b, a + b 6
Il est ´eventuellement possible de parler de proc´edure dans ce cas
Les param`etres d’une fonction peuvent ˆetre d´efinis avec une valeur par d´efaut. A l’utilisation de la fonction, ces param`etres sont alors optionnels. Dans le cas d’une fonction avec des param`etres optionnels, l’utilisation des param`etres doit ˆetre ordonn´ee, les param`etres sont affect´es dans l’ordre de leur d´efinition (ligne 6), ou nomm´ee (ligne 8). > > > d ef w e lc o me ( n a me , g r e et i ng = ’ H e l l o ’ , m ar k = ’ ! ’ ): ... print greeting , name , mark ... > > > w e lc o me ( ’ w o r l d ’ ) H el lo w or ld ! > > > w e lc o me ( ’ m o n d e ’ , ’ B o n jo u r ’ ) B on jo ur m on de ! > > > w e lc o me ( ’ w o r l d ’ , m ar k = ’ . .. ’ ) H el lo w or ld . ..
Python permet de d´efinir des fonctions anonymes, en utilisant la forme lambda 7 . Une telle fonction est r´eduite a` une simple expression. Cette construction est utile pour passer des fonctions en param`etre d’autre fonctions pour les configurer8 ou dans le cas des list mappings (voir section 1.2.5). > >> d ef c om pa re ( a, b , f un c =( l am bd a x , y: x < y )) : ... return func (a ,b ) ... > >> c om pa re ( 1 , 2 ) 1 > >> c om pa re ( 2, 1 , f un c =( l am bd a x , y: x > y )) 1
1.3.5
Documenter
La documentation fait partie int´egrante du code. En plus de la possibilit´e de mettre des commentaires avec l’utilisation de #, Python offre la possibilit´e d’´ecrire du code autodocument´e. Ceci est valable pour les fonctions, les classes et les modules. Une telle documentation d’un ´el´ement est accessible vie l’attribut __doc__ de ces diff´erents ´el´ements. Cette technique est utilisable automatiquement par les environnements int´egr´es de d´eveloppement ou par l’utilisation de la fonction help en mode interactif. La d´efinition des commentaires avec # devrait ˆetre r´eserv´e aux remarques techniques sur le code et pour les d´eveloppeur de l’´el´ement en question. La documentation doit quant `a elle ˆetre destin´ee au d´eveloppeurs mais surtout aux utilisateurs de l’´el´ement document´e. 7 8
Ici encore, cela sent la programmation fonctionnelle type Lisp `a plein nez. . . Nous verrons un peu plus tard que ce n’est pas la seule possibilit´e.
c 2003-2007, Rapha¨el Marvie
24
Premiers pas
Elle doit donc refl´eter le comportement de l’´el´ement. Cette seconde forme est a` mettre en parall`ele avec la javadoc. La d´efinition de la documentation se fait sur la premi`ere ligne apr`es la d´eclaration en utilisant des chaˆınes de caract`eres multi-lignes9 en utilisant des guillemets doubles (ligne 2-5). Une bonne mani`ere de d´efinir la documentation est de fournir une version courte sur une ligne, de passer une ligne et de fournir des d´etails. > >> d ef d um my ( ) : ... " "" Cette fonct ion est du pipeau ... ... ... Cette fonctio n est vrai ment du pipeau , ... elle ne fait a bso lum ent rien ." "" ... pass ... > > > h el p ( d u mm y ) H el p o n f un ct i on d um my i n m od ul e _ _m ai n __ : dummy() C et te f o nc ti on e st d u p ip ea u . .. C et te f o nc ti on e st v ra im e nt d u p ip ea u , e ll e n e f ai t a b so l um e nt r ie n .
1.4
Autres ´el´ements sur les s´equences
1.4.1
Fonctions de manipulation de s´ equences
Python offre un certain nombre de fonction permettant d’appliquer des traitements sur tous les ´el´ements d’une s´equence afin de d´efinir des filtres, d’appliquer des calculs pour tous ou de calculer des hashcode.
1.4.1.1
filter
La fonction filter applique la fonction pass´ee en premier argument sur chacun des ´el´ements de la s´equence pass´ee en second argument et retourne une nouvelle liste qui contient tous les ´el´ements de la s´equence pour lesquels la fonction a retourn´e une valeur vrai. > > > d ef f u nc t 1 ( v al ) : ... return val > 0 ... > >> f il te r ( fu nc t1 , [1 , -2 , 3 , -4 , 5 ]) [1 , 3 , 5] 9
Mˆ eme si la documentation tient sur une seule.
c 2003-2007, Rapha¨el Marvie
1.4 Autres ´ el´ ements sur les s´ equences
25
> > > d e f i s ev e n ( x ): ... return x % 2 ... > >> f il te r ( is ev en , [1 , 2 , 3 , 4 , 5 , 6 ]) [1 , 3 , 5]
1.4.1.2
map
La fonction map applique la fonction pass´ee en premier argument sur chacun des ´el´ements de la ou des s´equences pass´ees en param`etre. Dans le cas o` u plusieurs s´equences sont pass´ ees en param`etre, la fonction doit prendre autant de param`etres qu’il y a de s´equences. map retourne une liste contenant le r´esultat de chacun des calculs. > >> ... ... > >> [5 , > >> [1 ,
d ef s um (x , y ): return x + y map ( sum , [1 , 2 , 3 ], [4 , 5 , 6 ]) 7 , 9] m ap ( is ev en , [1 , 2 , 3 , 4 , 5 , 6 ]) 0 , 1 , 0 , 1 , 0]
1.4.1.3
reduce
La fonction reduce r´eduit une s´equence par l’application r´ecursive d’une fonction sur chacun de ses ´el´ements. La fonction pass´ee comme premier param`etre doit prendre deux arguments. La fonction reduce prend un troisi`eme param`etre optionnel qui est la valeur initiale du calcul r´ecursif. > >> r ed uc e (sum , [1 , 2 , 3 , 4 , 5 ]) 15 > >> r ed uc e (sum , [1 , 2 , 3 , 4 , 5] , -5) 10
1.4.2
Listes en compr´ ehension
La d´efinition de listes en compr´ehension10 permet de cr´eer des listes de mani`ere concise sans utiliser aux fonctions map, filter, etc. L’exemple suivant (ligne 2) permet d’appliquer une mˆeme op´eration a` tous les ´el´ements d’une liste. Cet exemple est donc similaire a` l’utilisation de la fonction map. La suite (ligne 4) permet de ne s´electionner que certains ´el´ements de la liste, ici les nombres impaires. Cet exemple est similaire a` l’utilisation de la fonction filter. La ligne 6 montre une combinaison des deux formes, en ´elevant au carr´e les nombres pairs de la liste foo. 10
Compr´ehension : Ensemble des caract`eres qui appartiennent `a un concept et servent `a le d´efinir. D´efinir a en extension . un ensemble en compr´ ehension . Par opposition `
c 2003-2007, Rapha¨el Marvie
26 >>> >>> [2 , > >> [1 , > >> [4,
Premiers pas foo = [1 , 2 , 3 , 4] [ elt * 2 for elt in foo ] 4 , 6 , 8] [ elt for elt in foo if elt % 2] 3] [ elt * *2 for elt in foo if elt % 2 is 0] 1 6]
Il est enfin a` noter que l’utilisation de ces constructions est en g´en´eral plus performante que l’utilisation d’une boucle for. En effet, leur mise en oeuvre est faite au coeur de l’interpr´eteur au lieu d’ˆetre interpr´et´ee.
1.4.3
It´erateurs et g´ en´erateurs
Les it´erateurs (PEP 234) et les g´en´erateurs (PEP 255) sont apparus avec les versions 2.2 et 2.3 de Python. Ils sont monnaie courante en Python 2.4.
1.4.3.1
It´ erateurs
L’apparition des it´erateurs a modifi´e la philosophie des boucles for pour le parcours de s´equences. Dans les version pr´ec´edentes de Python, l’it´eration sur une s´equence se faisait en utilisant l’index pour acc´eder aux ´el´ements de la s´equence. Lorsque la s´equence ´etait termin´ee, l’exception IndexError (voir section 3.4 pour les exceptions) signalait la fin de l’it´eration. D´esormais, un it´erateur est un objet (voir le chapitre 3 pour les objets) auquel on demande l’´el´ement suivant. Lorsqu’il n’y a plus de suivant, l’exception StopIteration signale la fin de l’it´eration. Les types de bases comme les listes, dictionnaires, tuples retournent d´esormais des it´erateurs pour leur parcours. Ces it´erateurs sont utilis´es automatiquement par les boucles for et par l’op´erateur in par exemple.
1.4.3.2
G´ en´erateurs
Les g´en´erateurs peuvent ˆetre consid´er´es comme une ´evolution des listes en compr´ehension. Syntaxiquement, les [] deviennent des (), comme le montre l’exemple suivant. Une des diff´erences entre les deux formes concerne l’utilisation de la m´emoire : un g´en´erateur ne construit pas toute la s´equence en m´emoire a priori , mais chaque ´el´ement de la s´equence est produit lorsque n´ecessaire. Pour obtenir une s´equence construite par un g´en´erateur, il suffit de passer le g´en´erateur en param`etre de la construction d’une liste11 (ligne 8). >>> ( elt * 2 for elt in foo ) >>> g = ( elt * 2 for elt in foo ) > >> g < g e n er a t or o b je c t a t 0 x 3 8c f8 0 > 11
En Python 2.4, la notation des listes en compr´ ehension revient `a la construction d’une liste `a partir d’un g´en´erateur.
c 2003-2007, Rapha¨el Marvie
1.4 Autres ´ el´ ements sur les s´ equences >>> ... 2 4 > >> >> [2 ,
27
for i in g : p r in t i , 6 8 l i s t( t ( el elt * 2 for elt in foo ) 4 , 6 , 8]
La d´efini efi niti tion on de d e fonc fo ncti tion onss g´en´ en´erat er ateu eurs rs se s e fait fa it en e n utili ut ilisa sant nt le l e mot mo t cl´ c l´e yield. Le L e d´erou er oule leme ment nt de la fonction est interrompu interrompu `a chaque chaque utilisation utilisation de yield, le reste res te sera ser a ´evalu´ evalu´e lorsqu lor squee l’app l’a ppela elant nt deman de mander deraa le prochai pro chain n ´el´ el´ement. eme nt. Le L e yield peut eu t ˆetre et re cons co nsid id´´er´ er ´e comm co mmee un return qui ne met pas fin a` l’ex´ecution ecut ion de la fonction. fonct ion. Lorsqu’il Lors qu’il est app appel´ el´e, e, un g´en´ en´erateur erat eur retourne reto urne un it´erateur, erat eur, ce qui permet per met une utilisation utilis ation dans une boucle for comme dans l’exemple l’exemple suivant. suivant. C’est l’utilisatio l’utilisation n de l’it´ l’it´erateur erateur retourn´ tou rn´e qui pilote pil ote le d´eroule ero ulement ment du g´en´ en´erateu era teurr : l’ex´ l’e x´ecutio ecu tion n s’arrˆ s’a rrˆete ete sur le yield qui est ´eval va lu´e a` chaque appel du suivant suivant sur l’it´erateur. erateur. > > > d ef e f g e n er er a t eu eu r ( ) : ... i = 0 ... while i < 10: ... yield i ... i += 1 ... > >> > > f or or i i n g en e n e ra ra t eu eu r ( ): ): ... print i , ... 0 1 2 3 4 5 6 7 8 9
1.4. 1.4.4 4
Bouc Boucle less for pr prob obl´ l´ emat em atiq ique uess
Certaines boucles de manipulation des listes peuvent ˆetre etre probl´ematiques, ematiques, par exemple si la boucle modifie la liste qu’elle est en train de parcourir. Pour que ce genre de boucle se passe bien, et ne soit pas sans fin, il est important dans certains cas de faire une copie de la liste pour le parcours et de travaille travaillerr sur la version version originale de la liste. Par d´efaut, efaut, tout argume arg ument nt est e st pass´ pas s´e par p ar r´ef´ ef´erence ere nce et don doncc sans s ans copie cop ie (en fait fai t copi c opiee de d e la l a list l istee des d es r´ef´ ef´erence ere ncess 12 et non des objets contenus) la boucle suivante serait sans fin . >>> > >> >> ... ... > >> >> [5 ,
a = [1 , -2 , 3 , -4 , 5 , -6] f o r e l t i n a [ : ]: ]: i f e l t > 0 : a . in i n s e r t (0 (0 , e l t ) a 3 , 1 , 1 , -2 , 3 , -4 , 5 , -6]
12
Cette boucle bouc le rajoute ra joute les ´el´ el´ements ements positifs posit ifs en d´ebut ebut de liste, comme le premier ´el´ el´ement ement est positif posi tif cette boucle bouc le est toujours toujou rs sur l’´el´ el´ement ement 1 alors que la liste ne fait que croˆ croˆıtre.
c 2003-2007, 2003- 2007, Rapha¨el el Marvie
28
1.5 1.5 1.5.1
Premiers pas
Exer Exerccice ices Manipulations de donn´ donn´ ees ees
Le fichier listetu.py contient une liste de 10 dictionnaires. Etudier cette structure de donn´ees ees et ´ecrire ecrire une fonction qui ´ecrit ecrit sur la sortie standard (en sautant une ligne entre chaque fiche) : dossier nom prenom u n i ve ve r s it it e d i s ci ci p l in in e niveau moyenne
: : : : : :
1 doe john l i ll ll e 1 i n f or or m a ti ti q u e 4 : 17
c 2003-2007, 2003- 2007, Rapha¨el el Marvie
Chapitre 2 Quelques modules et built-in 2.1 2.1.1
D´ efinition efinition et utilisation utilisation de modules D´ efinition efinitio n
Dans le chapitre chapitr e pr´ec´ ec´edent, edent, l’ensemble l’ense mble des extraits extra its de code cod e ont ´et´ et´e saisis interactiveinterac tivement. Cette Cett e m´ethode ethode n’est pas viable pour les traitements que l’on ex´ecute ecute plusieurs fois ou que l’on souhaite ex´ ecuter ecuter sur plusieurs plusieurs machines. machines. Pour rendre le code persistant, persistant, la premi` pre mi`ere ere soluti sol ution on est d’´ecrire ecr ire un programme , c’est-`a-dire a-dire de saisir le code dans un fichier texte avec l’extension .py. Un programme prog ramme peut pe ut ainsi ˆetre etre ex´ecut´ ecut´e plusieurs plusie urs fois. CepenCep endant, mˆeme eme si ce programme programme est correctement correctement structur´ structur´e avec avec des fonctions, fonctions, il n’est pas possible de r´eutiliser eutiliser facilement ces derni`eres eres (si ce n’est avec un copier-coller qui est une abomination). Pour capitaliser les d´eveloppement, eveloppement, Python propose la notion de module. Un module permet de fournir des biblioth`eques eques de fonctions, structures de donn´ees, ees, classes, a` int´ int ´egre eg rerr dans les programmes. Dans le cas de python, produire un module est identique a` produire un programme : faire un fichier. fichier. Les d´efinitions efinitions contenues contenues dans un fichier fichier sont utilisable globalement ou unitairement. Ainsi, le fichier examples.py peut pe ut ˆetre etr e utilis´ uti lis´e comme com me un module (nomm´e comme le fichier) et offrir l’acc`es es aux deux fonctions a` tout programme en ayant l’u l’utili tilit´ t´e1 . La chaˆ chaˆıne de documentat doc umentation ion doit ˆetre etre mise avant toute tou te d´eclaration eclar ation (c’est-` (c’es t-` a-dire aussi avant les clauses import) pou pourr ˆetre etre consid´er´ er´ee ee comme documentat doc umentation ion du module. mod ule. Les deux premi`eres eres lignes de ce fichier (optionnelles) (optionn elles) ont la significations significa tions suivante : – la premi` premi` ere ere ligne ligne de ce fichie fichierr indiqu indiquee que ce fichie fichierr sera reconnu reconnu comme comme un programme Python P ython par un environnement Unix (s’il a les droits en e n ex´ecution) ecution)2 ; – la seconde ligne pr´ecise ecise le type d’encodage du fichier : ici l’encodage standard en Europe occidentale supportant la gestion des accents. D`es es qu’un fichier Python contient un accent, accent, cette ligne est oligatoire oligatoire (dans le cas contraire elle peut ˆetre etre omise). ( (
1 2
) )
Si un programme a besoin de ces fonctions, c’est un programme tr`es es social au vu de leur utilit´e. e. . . La construction # ! sert `a pr´ eciser, eciser, sous Unix, le programme `a utiliser uti liser pour ex´ecuter ecuter un script. scri pt. ( (
29
) )
30
Quelques modules et built-in
#! /usr/bin/env python # -*- coding: iso-8859-1 -*# # examples.py # """ Regroupe les d´ efinitions des fonctions relatives au chapitre 1 de ‘Initiation a python par l’exemple’. """ def fib(n): """Calcule la suite de Fibonacci jusque n""" a, b = 0, 1 while b < n: print b, a, b = b, a + b def welcome(name, greeting=’Hello’, mark=’!’): """Un hello world configurable""" print greeting, name, mark
Utilisation d’un module La construction import permet d’importer un module et de fournir acc`es a` son contenu3 . L’importation d’un module peut se faire de deux mani`ere. La premi`ere solution est de d´esigner le module que l’on souhaite utiliser, son contenu est alors utilisable de mani`ere scop´ee , c’est-`a-dire en pr´efixant le nom de la fonctionnalit´e du nom du module (ligne 2). La seconde solution repose sur la construction from import o`u l’on identifie la ou les fonctionnalit´es que l’on souhaite importer d’un module (ligne 4)4 . L’utilisation se fait alors sans pr´efixer par le nom de module ( non scop´e ). Enfin, il est possible d’importer, avec cette seconde approche, tous les ´el´ements d’un module en utilisant la notation ‘*’ (ligne 7). ( (
) )
( (
) )
> > > i m po r t e x a mp l es > > > e x a mp l es . w e l c o me ( r a f i ) H el lo r af i ! > >> f ro m e xa m pl es i mp or t w el co me > > > w e lc o me ( r a f i ) H el lo r af i ! > >> f ro m e xa m pl es i mp or t * > > > f ib ( 1 0 0 ) 1 1 2 3 5 8 13 21 34 55 89 3 4
Nous consid´erons ici que l’interpr´eteur a ´et´e lanc´e dans le r´epertoire contenant le fichier examples.py. Dans le cas d’un import de plusieurs fonctionnalit´es, les noms sont s´epar´es par des virgules.
c 2003-2007, Rapha¨el Marvie
2.1 D´ efinition et utilisation de modules
31
Utilisation mixte Un fichier peut a` la fois d´efinir un module et un programme. Cette d´efinition mixte est int´ eressante pour, par exemple, utiliser les fonctionnalit´es d’un programme ind´ependamment de celui-ci, ou pour associer le code de test a` un module. Dans ce cas, la fin du fichier contient la d´efinition de l’initialisation du code comme un programme. Pour cela, un test est r´ealis´e afin de savoir si le code est import´e ou ex´ecut´e. Si le code est import´e, la variable __name__ contient le nom du module, sinon elle contient la chaˆıne ecution certaines des fonctions du module sont __main__ (ligne 1). Ici, dans le cas d’une ex´ test´ees. (Sinon il ne se passe rien.) i f _ _ na me __ = = ’ _ _m ai n __ ’ : welcome(’world’) w e lc o me ( ’ m o n d e ’ , ’ B o n jo u r ’ ) w e lc o me ( ’ w o r l d ’ , m a rk = ’ . . . ’ ) fib(100)
L’utilisation du fichier examples comme un programme donne la trace d’ex´ecution suivante. Que l’on utilise explicitement l’interpr´eteur ou non (du fait de la premi`ere ligne du fichier) la trace est identique. $ p y th o n e x am p l es . p y H el lo w or ld ! B on jo ur m on de ! H el lo w or ld . .. 1 1 2 3 5 8 13 21 34 55 89 \begin{verbatim} $ ls -l t o ta l 1 00 - rw xr - x - -- 1 r af i r af i 1 04 6 2 00 5 -0 3 -1 1 1 1 :5 1 e x am pl es . py * $ . / e x a mp l es . p y H el lo w or ld ! B on jo ur m on de ! H el lo w or ld . .. 1 1 2 3 5 8 13 21 34 55 89
Remarques Lors de l’utilisation de la construction import, l’interpr´eteur recherche la disponibilit´e des modules demand´e dans le chemin d´ecrit par la variable d’environnement efaut de cette variable contient le r´epertoire d’installation de PYTHONPATH. La valeur par d´ Python et le r´epertoire courant. Lors de l’utilisation de la construction from module import *, tout le contenu du module est import´e a` l’exception des d´efinition dont le nom commence par un ‘_’ (qui refl`etent la notion de priv´e en Python). L’utilisation de ce type d’importation all`ege le code saisi, ce qui est int´ eressant en interactif. Toutefois, une fois le pr´efixage par le nom de module perdu il peut de nouveau y avoir des conflits de noms entre les fonctionnalit´es import´ees depuis plusieurs modules. Enfin, les modules peuvent ˆetre organis´es selon une structure hi´erarchique. Dans ce cas, c 2003-2007, Rapha¨el Marvie
32
Quelques modules et built-in
les modules contenant des sous-modules, encore nomm´es packages, sont d´efinis comme des r´epertoires sur le syst`eme de fichier. Le nommage des modules se fait alors par concat´enation : epertoire doit contenir un fichier mod.submod. Afin de faciliter la portabilit´e du code, tout r´ nomm´e __init__.py. Pour permettre le chargement de tous les sous-modules, ce fichier doit contenir la liste des modules du package (r´eprtoire) stock´ee dans la variable __all__. $ c at g r ap h i ca l / _ _ i n it _ _ . p y _ _a ll __ = [ ’ b as ic ’ , ’ a d va nc ed ’ ]
2.2
Quelques modules standards et utiles
Python offre grand nombre de modules. Ne sont pr´esent´es ici que les quatre modules consid´er´es comme incontournables : etres et fonctions li´ees a` l’environnement d’ex´ecution, sys fournit les param` string fournit des op´erations courantes sur les chaˆınes de caract`eres (´equivalentes aux m´ethodes de la classe string), re fournit le support des expressions r´ eguli`eres pour faire du pattern matching et des
substitutions, os fournit l’acc`es aux services g´en´erique du syst`eme d’exploitation. Pour chacun de ces modules, les fonctionnalit´es de base sont pr´esent´ees et illustr´ees sur des exemples.
2.2.1
Le module sys
Quelques constantes
offertes par le module sys :
argv S´equence des param`etres pass´e sur la ligne de commande (argv[0] repr´esente le nom
du script). stdin stdout stderr Objets de type file repr´esentant les entr´ees et sorties standard. Ces objets peuvent ˆetre remplac´es par tout objet offrant une m´ethode write. path S´ equence contenant les chemins de la variable d’environnement PYTHONPATH. Cette
s´equence peut ˆetre manipul´ee dynamiquement. >>> sys.path.append(’/tmp/python’) [ ’ ’ , ’ / u sr / l i b / p y th o n2 . 2 ’ , ’ / u sr / l i b / p y th o n2 . 2 / p la t - l i n u x2 ’ , ’ / u s r / l i b / p y t h o n 2 . 2 / l i b - t k ’ , ’ / u sr / l i b / p y t h o n2 . 2 / l ib - d y n l o a d ’ , ’ / u s r / l i b / p y t h o n 2 . 2 / s i te - p a c k a g e s ’ , ’ / t m p / p y t h o n ’ ]
platform Nom du syst`eme d’exploitation. > > > s ys . p l a t fo r m ’darwin’
ps1, ps2 Variables contenant les valeurs des prompts, par d´ efaut ’>>>’ et ’...’.
c 2003-2007, Rapha¨el Marvie
2.2 Quelques modules standards et utiles
33
Quelques fonctions offertes par le module sys : ` l’ex´ecution d’un programme, arg ´etant le status de sortie. Cette exit([arg]) Mettre fin a fonction respecte le nettoyage des clauses finally (voir section 3.4.2.2).
2.2.2
Le module string
Ce module fournit un certain nombre de constantes et de fonctions de manipulation des chaˆınes de caract`eres. Il est g´en´eralement recommand´e d’utiliser les m´ethodes disponibles sur les objets de type string ´equivalentes.
2.2.2.1
Quelques constantes
Des constantes pratiques offertes par le module string d´efinissent des ensembles de caract`eres : > > > s t r i n g . l o w e r c a se ’abcdefghijklmnopqrstuvwxyz’ > > > s t r i n g . u p p e r c a se ’ABCDEFGHIJKLMNOPQRSTUVWXYZ’ > > > s t ri n g . l e tt e rs ’abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ’ > > > s t ri n g . d i gi t s ’0123456789’ > > > s t r i n g . w h i t e s p a ce ’ \ t \ n\ x 0 b \ x 0c \ r ’ > > > s t r i n g . p u n c t u a t i on ’!"#$%&\’()*+,-./:;<=>?@[\\]^_‘{|}~’
2.2.2.2
Les fonctions principales
lower upper cap* permettent de g´erer la casse d’une chaˆıne de caract`eres : mise en mi-
nuscules, en majuscules, capitalisation de la phrase ou des mots (avec la r´eduction des espaces). > > > s t ri n g . l o we r ( ’ F OO ’ ) ’foo’ > > > s t ri n g . u p pe r ( ’ f oo ’ ) ’FOO’ >>> string.capitalize(’foo’) ’Foo’ >> > s tr in g .c ap wo rd s (’ he llo ’ H e ll o W o rl d ! ’
wo rld ! ’ )
strip expandtabs permettent de g´ erer les espaces dans une chaˆıne de caract`eres en sup-
primant les blancs non significatifs ou en rempla¸cant les tabulations par un nombre fixe d’espaces. c 2003-2007, Rapha¨el Marvie
34
Quelques modules et built-in >> > st rin g .st ri p( ’ he ll o w orl d! \ n ’) # [2 nd a rg ] ’ he ll o w or ld ! ’ > > > s t ri n g . e x p an d t ab s ( ’ \ t h e ll o w o rl d ! ’ , 4 ) ’ hello world ! ’
a partir du d´ebut ou de la fin pour find permet de rechercher un motif dans une chaˆıne (` rfind) en retournant l’indice o` u le motif est trouv´e pour la premi`ere fois ou -1. (La fonction index est similaire mais l`eve une exception pour un motif non trouv´e.) > > > s t ri n g . f in d ( ’ b o n jo u r l e m o nd e ’ , ’ o n ’ ) 1 > > > s t ri n g . r f in d ( ’ b o n jo u r l e m o nd e ’ , ’ o n ’ ) 12 > > > s t ri n g . r f in d ( ’ b o n jo u r l e m o nd e ’ , ’ o m ’ ) -1
efaut sur les espaces, ou split permet de d´ecouper une chaˆıne en une liste de mots (par d´ alors sur une chaˆıne pass´ee en second argument) et join permet l’op´eration inverse qui est de construire une chaˆıne a` partir d’une liste de mots et une chaˆıne de liaison. > > > s t ri n g . s p li t ( ’ f oo b ar 1 23 ’ ) [ ’ f oo ’ , ’ ba r ’ , ’ 12 3 ’ ] > > > s t ri n g . s p li t ( " h e ll o w o rl d " , " w o " ) [ ’ h el lo ’ , ’ r ld ’ ] > > > s t ri n g . j oi n ( [ ’ f oo ’ , ’ b ar ’ , ’ 1 23 ’ ] , ’ ; ’ ) ’foo;bar;123’
count replace permettent respectivement de compter les occurence d’un motif dans une
chaˆıne et le remplacement de ce motif par un autre. > > > s t ri n g . c o un t ( ’ b o n jo u r l e m o nd e ’ , ’ o n ’ ) 2 > > > s t ri n g . r e pl a ce ( ’ b o n j ou r l e m o nd e ’ , ’ o n ’ , ’ O N O N ’ ) ’ b O N ON j o ur l e m O NO N de ’
zfill center rjust ljust permettent de g´erer l’affichage : zfill compl`ete un nombre
avec des z´eros en tˆete pour une largeur d’affichage constant, les trois autres fonctions permettent de justifier une phrase sur une largeur donn´ee. > > > s t ri n g . z f il l ( s t r ( 12 3) , 5 ) ’00123’ > > > s t ri n g . c e nt e r ( ’ hi ! ’ , 1 0) ’ hi ! ’ > > > s t ri n g . r j us t ( ’ h i ! ’ , 1 0) ’ hi ! ’ > > > s t ri n g . l j us t ( ’ h i ! ’ , 1 0) ’ hi ! ’
c 2003-2007, Rapha¨el Marvie
2.2 Quelques modules standards et utiles
2.2.3
35
Le module re
Ce module permet la manipulation des expressions r´eguli`eres [2]. Ces expressions sont par d´efaut identiques `a Perl et l’ouvrage Mastering Regular Expressions de Jeffrey Friedl (O’Reilly) est un bon compl´ement pour qui doit utiliser les expressions r´eguli`eres. Afin de ne pas devoir toujours utiliser des ‘\’ dans les expressions, il est possible d’utiliser des Raw regular expressions en pr´efixant la chaˆıne d´efinissant l’expression par un ‘r’ : r’(.*)\n’. La derni`ere question qu’il faut se poser avant de commencer a` utiliser les expressions r´eguli`eres est l’encodage support´e. Le module re peut utiliser l’un ou l’autre de ces deux modules : – sre Support unicode (module utilis´e par d´efaut, impl´ementation masqu´ee par re) – pre Sans support unicode (mais ce module est d´esormais deprecated ) ( (
2.2.3.1
) )
Op´ erations de recherche
search(pattern, chaine) permet de rechercher le pattern dans la chaˆıne et retourne un objet de type SRE_Match d´ecrivant la r´eponse ou bien None. La classe SRE_Match fournit des m´ethodes pour obtenir l’indice de d´ebut (start()) et de fin (end()) du motif dans la chaˆıne. Ici, la m´ethode matching utilise span() qui fournit un tuple
contenant les deux indices. > > > d ef m a tc h i ng ( r e s ) : ... if res : print res .span () ... else : print ’ no m atching ’ > > > m a t ch i ng ( r e . s e a rc h ( ’ a da ’ , ’ a b r a ca d a br a ’ ) ) (5 , 8 )
match(pattern, chaine) test si la chaˆıne commence par le pattern et retourne un ob jet de type SRE_Match d´ecrivant la r´eponse ou bien None. > >> r es = r e . ma tc h ( ’ ab r ’ , ’ a b ra c ad a br a ’ ) > > > m a t ch i ng ( r e s ) (0 , 3 )
2.2.3.2
Op´ erations de manipulation
ecoupe la chaˆıne par rapport au pattern. L’exemple suivant split(pattern, chaine) d´ fait un d´ecoupage en mots (tout ce qui n’est pas espace ou ponctuation). > >> r e . sp li t ( ’\ W + ’, ’ H el lo w or ld ! ’ ) [ ’ H el lo ’ , ’ w or ld ’ , ’ ’ ]
sub(pattern, repl, chaine) retourne une chaˆıne ou toutes les occurences du pattern dans la chaˆıne fournie sont remplac´es par repl. La chaˆıne n’est pas modifi´ee, une
copie est cr´e´ee. > >> r e . su b ( ’ he ll o ’ , ’ b on jo ur ’ , ’ h el lo f oo h el lo b ar ’ ) ’ b on jo ur f oo b on jo ur b ar ’
c 2003-2007, Rapha¨el Marvie
36
Quelques modules et built-in
2.2.3.3
Utilisation d’expressions compil´ ees
Lorsqu’une expression r´eguli`ere est utilis´ee de mani`ere r´ep´etitive dans un programme, il devient int´ eressant de compiler le pattern. Les fonctionnalit´es sont similaires a` celles vues pr´ec´edamment (m´ethodes) mais la performance est meilleure. compile permet la cr´eation d’un objet repr´esentant l’expression r´eguli`ere sous forme
compil´ee. Un fois l’objet cr´e´e, les fonctions sont appel´ees sur cet objet et non par rapport au module. La m´ethode group() sur l’objet SRE_Match donne acc`es au i-`eme motif (dans le cas d’une expression compos´ee de plusieurs motifs5 comme ici) trouv´e par la fonction search. > > > e xp = r e . c o mp i le ( ’ < a h r ef = " ( . *) " > ( . *) < / a > ’ ) > > > r es = e xp . s e a r ch ( ’ C l i q ue r < a h r ef = " f o o . h tm l " > ic i < / a > ! ’ ) > > > m a t ch i ng ( r e s ) ( 8 , 3 4) > > > r es . g r o up ( 0 ) ’ < a h re f = " f oo . h t m l " > ic i < / a > ’ > > > r es . g r o up ( 1 ) ’foo.html’ > > > r es . g r o up ( 2 ) ’ici’ > > > e xp = r e . c o mp i le ( r ’ . * < a h r ef = " ( .* ) " > .* < / a > . * ’ ) > > > e xp . s u b ( r ’ \1 ’ , ’ C l i qu e r < a h re f = " f oo . h t m l " > ic i < / a > ! ’ ) ’foo.html’
2.2.4
Le module os
Ce module permet d’acc´eder aux fonctions des syst`emes d’exploitation et de faire de la programmation syst`eme ou de l’administration. Les fonctions sont disponibles sur (presque) tous les syst`eme. Toutefois, il faut toujours ˆetre conscient des limites pour la portabilit´e du code : la notion de droits sur un fichier n’est pas similaire sur tous les syst`emes. Les principaux sous modules de os sont : – path manipulation de chemins, – glob fnmatch pattern matching de fichiers et r´epertoires, – time acc`es et manipulation de l’heure, – getpass manipulation de mots de passe et identifiants. utilisateur
2.2.4.1
Quelques constantes
name donne le nom de l’implementation du module os : posix, nt, dos, mac, java,
etc. environ Dictionnaire contenant les variables d’environnement (au sens Unix mais aussi
relatives au lancement de l’interpr´eteur Python). 5
Un motif au sein d’une expression r´eguli`ere est d´efini par des parenth`eses.
c 2003-2007, Rapha¨el Marvie
2.2 Quelques modules standards et utiles
37
> > > o s . e n vi r on { ’ U S ER ’ : ’ r a fi ’ , ’ H O ME ’ : ’ / h om e / r a fi ’ , ’ P A T H ’ : ’/ b i n : / u s r / b i n : / o p t / b i n : / h o m e / r a f i / b i n ’ , ’ H O S TN A ME ’ : ’ a l fr i . l i fl . f r ’ , ’ P W D ’ : ’ / h o me / r a f i / e n s e i g n / p y t h o n / s c r i p t s ’ }
2.2.5
Le module os.path
Ce module fournit quelques primitives (courantes sous Unix) de manipulation des noms de fichiers et des fichiers. basename dirname permettent respectivement d’extraire d’un chemin le nom du fichier
ou le nom du r´epertoire (ou de l’arborescence dans le cas d’un chemin compos´e). >>> os.path.basename(’/tmp/foo.txt’) ’foo.txt’ >>> os.path.dirname(’/tmp/foo.txt’) ’/tmp’
split join permettent respectivement de d´ecouper et de construire un chemin. L’utilisation de la fonction join est fortement recommand´ee pour construire des chemin
car elle respecte implicitement le bon s´eparateur de chemin pour le syst`eme courant. >>> os.path.split(’/tmp/foo.txt’) ( ’ / t mp ’ , ’ f oo . t x t ’ ) > > > o s . p at h . j o in ( ’ / t m p ’ , ’ f oo . t x t ’ ) ’/tmp/foo.txt’
exists isdir isfile permettent de tester l’existance et le type d’un fichier (ou r´epertoire). >>> os.path.exists(’/tmp/bar.txt’) False > > > o s . p at h . i s di r ( ’ / t mp ’ ) True > > > o s . p at h . i s f il e ( ’ / t mp ’ ) False
2.2.6
Les modules glob et fnmatch
Ces deux modules fournissent principalement une fonction portant le mˆeme nom. equivalent du ls Unix. Cette fonction retourne une liste des fichiers d’un glob est l’´ r´epertoire avec utilisation de jockers. > > > g l ob . g l o b ( ’ *. p y ’ ) [ ’ h e ll o . p y ’ , ’ e x a mp l es . p y ’ ] >>> glob.glob(’/tmp/*.tmp’) [ ’ / t mp / s v 3 e2 . t m p ’ , ’ / t mp / s v 0 01 . t m p ’ , ’ / t mp / s v 3 e4 . t m p ’ ]
c 2003-2007, Rapha¨el Marvie
38
Quelques modules et built-in
fnmatch et filter permettent de faire du pattern matching sur des chaˆınes de caract`eres
repr´ esentant des noms de fichiers : respectivement est ce qu’un nom suit un pattern de nommage et quels sont les ´el´ements d’une liste respectant un pattern. > > > f n ma t ch . f n m a t ch ( ’ e x a m p le s . p y ’ , ’ * . py ’ ) 1 > > > f n ma t ch . f i l t er ( [ ’ e x a m pl e s . p y ’ , ’ h e ll o . p y c ’ ] , ’ * . py ’ ) [’examples.py’]
2.2.7
Le module getpass
Ce module permet de demander au syst`eme le nom de l’utilisateur connect´e et de demander de mani`ere cach´ee un mot de passe. ( (
) )
eme le nom de login de l’usager getuser() demande au syst` > > > g e tp a ss . g e t u s er ( ) ’rafi’
getpass() demande proprement (en masquant les caract`eres saisis) un mot de passe a`
l’usager. L’appel a` cette fonction est bloquant jusqu’`a ce que l’usager ait tap´e entr´ee. > >> p = g et pa ss . g e tp as s ( ) # b l oq ua n t j us qu ’ a u ’\ n ’ Password: > >> p ri nt p ’quelmauvaismotdepasse’
2.3
Built-in en Python
Les built-in sont les fonctionnalit´es cabl´ees en dur dans l’interpr´eteur Python, et dans un certain sens l’interpr´eteur lui-mˆeme. Ces fonctionnalit´es ne sont pas ´ecrite en Python car elles sont plus que largement utilis´ees et leur mise en œuvre en C contribue a` obtenir de meilleures performances.
2.3.1
Les fichiers
2.3.1.1
Les objets fichiers
Les fichiers sont repr´esent´es comme des objets de type file. Ils peuvent ˆetre textuels ou binaires et ˆetre utilis´es en lecture ou en ´ecriture. open ouvre un fichier (cr´ee l’objet associ´e) en lecture par d´efaut. > >> f oo = o pe n ( ’/ t mp / f oo . t xt ’ ) > >> f oo < o p en f i le ’ / t mp / f o o . t xt ’ , m o de ’ r ’ a t 0 x 8 1a 3 fd 8 >
c 2003-2007, Rapha¨el Marvie
2.3 Built-in en Python
39
close ferme un fichier (mais ne d´etruit pas l’objet associ´e). > > > f oo . c l o se ( ) > >> f oo < c l os e d f i le ’ / t mp / f o o . t xt ’ , m o de ’ r ’ a t 0 x 8 1a 3 fd 8 >
2.3.1.2
Lecture dans un fichier
Il y a plusieurs mani`eres de lire un fichier. ` la fois readline() permet de lire une ligne (position courante jusqu’au prochain \n) a dans le fichier. > >> f oo = o pe n ( ’/ t mp / f oo . t xt ’ , ’ r ’) > > > p r in t f oo . r e a d li n e ( ) ’ h e ll o w o rl d ! \ n ’
readlines() permet de lire toutes les lignes d’un fichier en une seule fois (retourne une
s´equence de chaˆınes). > > > f oo . r e a d l in e s ( ) [ ’ b on jo ur l e m on de ! \ n ’, ’ au r ev oi r l e m on de ! \ n ’]
` partir de la position courante, ou au maximum n read([n]) permet de lire tout le fichier a octets lorque un argument est donn´e. Cette fonction retourne une chaˆıne. La fonction eplacer dans le fichier de fa¸ con absolue : ici nous retournons au seek permet de se d´ d´ebut (indice 0). > >> f oo . s ee k ( 0) ; f oo . r ea d () ’ h el lo w or ld ! \ n b on jo ur l e m on de ! \ n au r ev oi r l e m on de ! \ n ’ > > > f oo . c l o se ( )
Comparaison des approches de lecture Il n’y a pas de solution id´eale pour la lecture des fichiers. Il faut choisir en fonction de la situation et des besoins. – La lecture globale (readlines) d’un fichier est plus performante pour l’aspect r´ecup´eration des informations car elle repr´esente un gros acc`es disque puis un parcours de s´equence en m´emoire. Toutefois, cette approche est coˆ uteuse en m´emoire vive : imaginez la pr´esence d’un fichier texte de 500Mo en m´emoire. – Lecture ligne par ligne (readline) est plus coˆ u teuse pour lire un fichier car elle repr´esente de nombreux acc`es disques pour des petites quantit´es d’information. Toutefois, cette approche permet de manipuler des gros fichiers : un fichier de 10Go peut ˆetre lu ligne par ligne sur une machine ayant 64Mo de m´emoire. Depuis Python 2.3, il est possible d’it´erer simplement ligne par ligne sur un fichier ouvert (sans avoir a` utiliser la fonction readline). Cette mani`ere de faire repose sur les it´erateurs (voir la section 1.4.3.1). c 2003-2007, Rapha¨el Marvie
40
Quelques modules et built-in
> > > f i ch i e r = o p en ( ’ / t m p / f oo . t x t ’ ) > >> f or l in e i n f ic hi er : ... print line .strip () . .. f i ch i e r . c lo s e ( ) ... h e ll o w o rl d ! b on jo ur l e m on de ! a u r ev oi r l e m on de !
2.3.1.3
Ecriture dans un fichier
Il faut qu’un fichier soit ouvert en ´ecriture pour pouvoir ´ecrire dedans, on le pr´ecise donc `a l’ouverture en donnant un second param`etre ’w’ (Python suit les modes d’ouverture du langage C, pour les fichiers binaires il faut pr´eciser ’b’ en plus). Tant que le fichier n’est pas ferm´e, son contenu n’est pas garanti sur le disque. write permet d’´ecrire des donn´ees (une chaˆıne de texte) repr´esentant une ou plusieurs lignes de texte (utilisation de ‘\n’). Les donn´es peuvent aussi ˆetre binaires. > >> f oo = o pe n ( ’/ t mp / f oo . t xt ’ , ’ w ’) > > > f oo . w r i te ( ’ h e l lo w o rl d ! \ n ’ )
writelines permet d’´ecrire des donn´ees contenues dans une s´ equence (de chaˆınes). Si
chaque chaˆıne contenue dans la s´equence repr´esente une ligne de texte dans le fichier, il faut alors qu’elles contiennent toute la s´equence de fin de ligne ‘\n’. Dans le cas contraire, tout sera ´ecrit dans le fichier, mais la notion de ligne sera d´efinie par les \n contenus (mˆeme s’ils n’´ etient pas en fin d’une des chaˆınes). > >> l in es = [ ’ b on jo u r l e m on de ! \ n ’ , ’ a u r ev oi r l e m on de ! \ n ’] > > > f oo . w r i t e li n e s ( l i ne s ) > > > f oo . c l o se ( )
2.3.2
Conversions de type
Utilisation du nom des types pour convertir les chaˆınes, en entiers, flottants, etc. (et r´eciproquement.) La fonction str permet de convertir tout objet en chaˆıne. > > > s tr ( 1 2 3 ) ’123’ > > > i nt ( ’ 1 2 3 ’ ) 123 > > > f l oa t ( ’ 1 23 ’ ) 123.0 > > > f l oa t ( 1 2 3) 123.0 > > > l o ng ( ’ 1 2 3 ’ ) 123L
c 2003-2007, Rapha¨el Marvie
2.3 Built-in en Python
41
Mais Attention aux arrondis > > > f l oa t ( ’ 1 2 .3 ’ ) 12.300000000000001
2.3.3
Evaluation dynamique
Python permet d’ex´ecuter des commandes a` la vol´ee6 : une chaˆıne de caract`eres repr´esentant une commande est execut´ee. La chaˆıne peut ˆetre compil´ee explicitement ou non avant son ´evaluation. Cette possibilit´e permet de faire de la g´en´eration dynamique de commandes. compile() retourne une version compil´ee de l’expression (ou du fichier) pass´e en pa-
ram`etre. Le second argument pr´ecise o` u doit se faire la sortie d’erreur au cas o` u une exception serait lev´ee. Le dernier argument pr´ecise quel usage est envisag´e, ici nous pr´evoyons de l’utiliser avec la fonction eval() > >> o bj = c om pi le ( ’ x + 1 ’ , ’ < st ri ng > ’ , ’ ev al ’ ) > >> o bj < c od e o bj ec t ? a t 0 x 81 68 5d 8 , f il e " < s tr in g > " , l in e -1 >
eval() ´evalue une expression (compil´ ee ou non) pass´e en param`etre. >>> x = 2 > >> e va l (’ x + 1 ’) 3 > > > e v al ( o b j ) 3
2.3.4
Assertions
Les assertions permettent de traiter les situations sans appel : soit la condition est respect´ee, soit le programme est arrˆet´e. (Dans la pratique, une exception est lev´ee.) ete le programme en affichant un message assert ´evalue une expression logique et arrˆ d’erreur (qui est optionnel et fourni s´epar´e par une virgule) si l’expression logique est fausse (cf section 1.3.2). L’expression peut inclure des appels de fonctions. > >> a ss er t 1 > >> a ss er t 0 , ’ o up s ’ T ra c eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 1 , in ? A s s er t i on E r r or : o u ps > >> t ry : a ss er t 0 . .. e x ce p t A s s e rt i o nE r r or : p r in t ’ s ic ’ ... sic 6
Bien que tout est dynamiquement ´evalu´ e en python, il est possible de faire des choses encore plus dynamiquement.
c 2003-2007, Rapha¨el Marvie
42
2.4 2.4.1
Quelques modules et built-in
Exercices Utilitaire de sauvegarde
En s’aidant de la fonction os.stat qui permet de connaˆıtres la dates de modification des fichiers, ´ecrire un utilitaire de backup d’une arborescence. Cet utilitaire doit faire un backup incr´emental (sauf la premi`ere fois) des fichiers modifi´es. > > > p r in t o s . s ta t . _ _ d oc _ _ s t at ( p a t h ) - > ( s t _m o de , s t_ in o , s t_ de v , s t_ n li nk , s t _u i d , s t _g i d , s t _ si z e , s t _ at i m e , s t _ mt i m e , s t _ c t i me ) P er fo rm a s ta t s ys te m c al l on t he g iv en p at h .
2.4.2
Extraction de donn´ ees
Cet exercice propose d’utiliser des fonctions du module regular exressions pour extraires des donn´ees d’un fichier texte. Ecrire un programme analysant un fichier texte de type mbox et qui produit la liste de toutes les personnes ayant envoy´e un e-mail, en triant la liste de leurs adresses par ordre alphab´etique avec la date de l’e-mail re¸cu le plus r´ecent.
c 2003-2007, Rapha¨el Marvie
Chapitre 3 Plongeon dans les objets 3.1 3.1.1
Des objets, que des objets Rappels des principes de base de POO
Instanciation Un ob jet est cr´e´e a` partir d’un moule, sa classe qui d´efinit une structure (les attributs) et un comportement (les m´ethodes). Une classe d´efinit un type d’objets. Un objet est instance d’une unique classe. Encapsulation Les donn´ees sont cach´ees au sein des objets, et leur acc`es est contrˆ ol´e par les m´ethodes. L’´etat d’un objet ne devrait pas ˆetre manipul´e directement. L’objet peut ˆetre vu comme un fournisseur de services (et non de donn´ees). ( (
) )
Polymorphisme Des objets respectant une mˆeme interface (la signature de m´ethodes suffit dans le cas de Python) peuvent ˆetre manipul´es de mani`ere g´en´erique, mˆeme si leur type exact est diff´erent. Ce principe permet aussi la substitution d’une instance par une autre (tant que les interfaces sont compatibles). H´eritage M´ecanisme qui permet la r´eutilisation de d´efinitions de base, comportements par d´efaut, et la sp´ecialisation de certains comportements. La relation entre d’h´eritage entre deux classes ne se limite pas `a une facilit´e de capitalisation de code. La classe qui h´erite doit ˆetre un de la classe dont elle h´erite : un chat est un animal, chat peut donc ˆetre une sous classe de animal. ( (
3.1.2
) )
( (
) )
Objets et r´ ef´ erences
En Python, le monde est uniforme. – Tout est ob jet : les chaˆınes, les entiers, les listes, les fonctions, les classes, les modules, etc. Tout est r´eifi´e et manipulable dynamiquement. – Tout objet est manipul´e par r´ef´erence : une variable contient une r´ef´erence vers un objet et un objet peut ˆetre r´ef´erenc´e par plusieurs variables. – Une fonction, une classe, un module sont des espaces de nommage organis´es de mani`ere hi´erarchique : un module contient des classes qui contiennent des fonctions 43
44
Plongeon dans les objets (les m´ethodes).
3.1.3
Classes
3.1.3.1
D´ efinition et instanciation
La d´efinition d’une classe suit la r`egle des blocs (cf section 1.3.1) en utilisant le mot cl´e ethode est d´efinie comme une fonction avec un premier argument (self) class. Toute m´ qui repr´esente l’objet sur lequel elle sera appliqu´ee a` l’ex´ecution. En Java ou C++, le this est d´efinie implicitement, en Python il est explicite est c’est toujours le premier param`etre d’une m´ethode. Le nom est libre, mais on utilise en g´en´eral self. Une m´ethode ne prenant pas de param`etres aura donc quand mˆeme un argument. > >> c la ss D um my : ... def hello (self ): ... print ’ hello world ! ’
L’instanciation se fait sans mot cl´e particulier (il n’y a pas de new en Python). Il suffit de faire suivre un nom de classe de parenth`eses (contenant ou non des param`etres) pour d´eclancher une instanciation. L’invocation se fait a` l’aide de la notation point´ee, un appel de m´ethode sur une variable r´ef´eren¸ cant un objet. > >> d = D um my ( ) > >> d < _ _ m ai n __ . D u m m y i n st a n ce a t 0 x 8 17 b1 2 4 > > > > d . h e ll o ( ) h e ll o w o rl d !
3.1.3.2
D´ efinition d’attributs et du constructeur
Les attributs sont d´efinis a` leur premi`ere affectation. Une variable est consid´er´ee comme un attribut si elle est rattach´ee `a l’objet : elle est acc´ed´ee par self. Tout acc`es a` un attribut ou a` une m´ethode de l’objet depuis sa mise en oeuvre se fait obligatoirement par la variable self. Le constructeur est une m´ethode nomm´ee __init__. Comme toute m´ethode, certain de ses param`etres peuvent avoir des valeurs par d´efaut. Cette possibilit´e est important car une classe a un seul constructeur en Python (contrairement a` d’autre langages). ( (
) )
( (
) )
> > > c l as s C o m pt e ur : ... def __ init__ (self , v =0): ... self . val = v ... def value (self ): ... return self . val
En termes de g´enie logiciel (et de bon sens), il est recommand´e de toujours initialiser l’´ etat des objets (ses attributs) lors de son l’instanciation, donc dans le constructeur. D’autre part, un constructeur qui ne fait rien n’est pas stupide ! Il dit clairement ce qu’il en est : l’absence de constructeur ne serait pas un oubli. c 2003-2007, Rapha¨el Marvie
3.1 Des objets, que des objets
45
Visibilit´ e des attributs et m´ ethodes Les attributs, comme les m´ethodes, ont par d´efaut une visibilit´e publique en Python. Dans le cas des instances de la classe Compteur, il est possible de manipuler directement la valeur de l’attribut (ou m´ethodes) val. Une convention en Python est de pr´efixer les attributs par un souglin´e pour annoncer qu’ils ne sont pas destin´es a` ˆetre utilis´es par les clients. Il est a` noter que c’est une convention et rien n’empˆeche un utilisatieurde lire un attribut dont le nom est pr´efix´e par un soulign´e1 . Enfin, l’utilisation de deux soulign´es comme pr´efixe (et pas de soulign´e comme postfixe) d’un nom d’attribut (ou de m´ethode) permet de d´efinir un attribut priv´e et donc non visible par les clients de la classe. ( (
) )
( (
) )
> >> c la ss F oo : ... def __ init__ ( self ): ... self . _a = v ... self . __b = 1 ... > >> f = Foo () > >> f . _a 0 > > > f . _ _b T r ac eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 1 , in ? A t t r ib u t eE r r or : C o mp t e ur i n st a n ce h as n o a t t ri b u te ’ _ _b ’
3.1.4
H´ eritage
Python supporte l’h´eritage simple et l’h´eritage multiple. Dans une relation d’h´eritage, il est faut pr´eciser le nom de la classe m`ere (entre parenth`eses apr`es le nom de la classe en cours de d´efinition) et appeler explicitement le constructeur de la super classe. c la ss A : d ef _ _ in i t __ ( s e lf , n = ’ n o ne ’ ) : s el f . _ na me = n d ef n a me ( s e l f ) : r e t u rn s e l f . _ n a m e c l as s B ( A ) : d ef _ _ in i t __ ( s e lf , v al = 0 , n = ’ n o ne ’ ) : A . _ _ i n it _ _ ( s el f , n ) s e lf . _ w h e el s = v al d ef w h ee l s ( s e lf ) : r e t u rn s e l f . _ w h e e l s
Dans le cas de l’h´eritage multiple, il suffit de pr´eciser les diff´erentes classes m`eres et d’appeler leurs constructeurs respectifs. 1
Il est vrai que dans le cas de Python la notion de prot´eg´e repose sur la confiance, mais si vous roulez `a 180 Km/h en ville qui est responsable, la voiture ou vous ?
c 2003-2007, Rapha¨el Marvie
( (
) )
46
Plongeon dans les objets
c la ss C : d ef _ _ in i t __ ( s e lf , t = ’ ’ ): s el f . _ ti tl e = t d ef t i tl e ( s e lf ) : r e t u rn s e l f . _ t i t l e c la ss D ( A , C ) : d ef _ _ in i t __ ( s e lf , n = ’ n o ne ’ , t = ’ ’ ): A . _ _ i n it _ _ ( s el f , n ) C . _ _ i n it _ _ ( s el f , t ) d ef f u ll n a me ( s e l f ) : r et ur n s el f . _ ti tl e + ’ ’ + s el f . _ na me
L’exemple suivant donne une utilisation des trois classes pr´ec´edentes. Il n’y a rien de particulier a` l’utilisation que la classe ait ´et´e d´efinie enti`erement ou par h´eritage ne change rien. > >> a = A ( ’r af i ’) > > > p r in t a . n a me ( ) rafi > >> b = B (4 , ’ car ’ ) > > > p r in t b . n a me ( ) car > > > p r in t b . w h e el s ( ) 4 > >> d = D (t = ’dr ’ ) > > > p r in t d . f u l ln a me ( ) d r n on e
H´ eritage multiple probl´ ematique L’h´eritage multiple pose probl`eme lorsque deux classes h´erit´ees offre une m´ethode portant le mˆeme nom. Dans ce cas, il est possible de pr´efixer les m´ethodes par le nom de la classe qui les d´efinies ou d’utiliser des alias de m´ethodes pour r´esoudre les conflits. c la ss X : d ef n a me ( s e l f ) : re tu rn ’I am c la ss Y : d ef n a me ( s e l f ) : re tu rn ’I am c la ss Z ( X , Y ) : x na me = X . n am e y na me = Y . n am e d ef n a me ( s e l f ) : re tu rn ’I am ’ a nd
an X ’
an Y ’
an Z , ie ’ + se lf . xna me () + \ ’ + s el f . yn am e ()
c 2003-2007, Rapha¨el Marvie
3.2 Structures des objets
47
L’exemple suivant propose une utilisation des trois classes X, Y, Z pr´ec´edentes avec une invocation de la m´ethode name() sur les trois instances cr´e´ees. > >> for ... ... ... I am an I am an I am an
3.1.5
c lss in [ X, Y , Z ]: obj = clss () print obj .name () X Y Z , ie I am an X and I am an Y
Classes vs modules
Il semblerait que la vision suivante doit bien accept´ee de la communaut´e de d´eveloppeurs Python2 : – Utiliser des classes lorsque – Les donn´ees repr´esentent un ´etat et doivent ˆetre prot´eg´ees. – Les traitements et donn´ees sont fortement li´es (les donn´ees ´evoluent). – Utiliser des modules de fonctions lorsque – Les traitements et donn´ees sont ind´ependants (ex : data mining). – Les donn´ees sont stock´ees dans des BD ou fichiers, et non modifi´ees. ( (
3.2 3.2.1
) )
Structures des objets Introspection simple
La fonction dir() donne le contenu de tout objet (liste de ses attributs et m´ethodes). Associ´ee a` l’attribut __doc__, cela fournit une documentation de base sur tout objet. D’o` u l’int´erˆet de bien auto-documenter le code (voir section 1.3.5). > > > d ir ( C o m p t eu r ) [ ’ _ _ d oc _ _ ’ , ’ _ _ i ni t _ _ ’ , ’ _ _ m od u l e_ _ ’ , ’ v a lu e ’ ] > >> c = C om pt eu r () > > > d ir ( c ) [ ’ _ _ d oc _ _ ’ , ’ _ _ i ni t _ _ ’ , ’ _ _ m od u l e_ _ ’ , ’ v al ’ , ’ v a lu e ’ ]
La fonction type() donne le type d’une r´ef´erence. > > > t yp e ( c ) < t y pe ’ i n s ta n c e ’ > > >> t yp e ([ 1 , 2 ]) < t y pe ’ l i st ’ > 2
Personnellement tout est d´efini comme des classes, no comment. . .
c 2003-2007, Rapha¨el Marvie
48
3.2.2
Plongeon dans les objets
Classes et attributs
Une classe ne contient que des attributs. Elle peut ˆetre vue comme un simple dictionnaire contenant des associations nom / r´ef´erence. Une fonction de la classe (ou m´ethode) est en fait un attribut qui est ex´ecutable (callable ). > > > c l as s O n e Tw o T hr e e : ... value = 123 # r e fe r en ce u n e nt ie r ... def fu nction ( self ): # r e fe re n ce u ne f on ct i on ... return self . value ... > >> o tt = O n eT wo T hr ee ( ) > > > d ir ( o t t ) [ ’ _ _ d oc _ _ ’ , ’ _ _ m o du l e __ ’ , ’ f u n ct i on ’ , ’ v a lu e ’ ] > > > o tt . f u n c t io n < b o un d m e th o d O n e Tw o T hr e e . f u n c ti o n o f < _ _ m ai n _ _ . O n e Tw o T hr e e
Dans le cas d’un conflit de nom entre un attribut et une m´ethode, la priorit´e va a` l’attribut. Ici, l’interpr´eteur explique que l’on ne peut utiliser l’attribut name comme si c’´etait une fonction (ou m´ethode) car c’est une chaˆıne, donc on ne peut demander son ex´ecution (object is not callable). La m´ethode name est masqu´ee par l’attribut portant le mˆeme nom. > > > c l as s C o n fl i ct : ... def __ init__ ( self ): ... self . name = ’ Confl ict ’ ... def name ( self ): ... return ’ You will never get this string !’ ... > >> c = C on fl ic t () > > > c . n a me ( ) T r ac eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 1 , in ? T y pe Er r or : ’ s tr ’ o bj ec t i s n ot c al la bl e
L’utilisation syst´ematique d’attributs prot´eg´es est donc une bonne id´ ee qui a pour cons´equence d’´eviter les conflits de noms entre attributs et m´ethodes. ( (
) )
> > > c l as s N o C on f l ic t : ... def __ init__ ( self ): ... self . _name = ’ No Con fli ct ’ ... def name ( self ): ... return self . _name ... > >> c = N o Co n fl i ct ( ) > > > p r in t c . n a me ( ) NoConflict
c 2003-2007, Rapha¨el Marvie
3.3 Les objets, version avanc´ ee
49
Il est possible de d´efinir dynamiquement des attributs sur une classe ou une instance. Ce genre de facilit´e ne se limite pas `a l’aspect ludique, c’est parfois la meilleure solution a` un probl`eme. Toutefois, attention o` u l’on met les pieds lorsque l’on modifie dynamiquement des ob jets. > >> c la ss E mp ty : ... pass > >> E mp ty . v al ue = 0 > > > d ef f u nc t ( s e lf ) : ... self . value += 1 ... return self .value ... > >> E mp ty . f u nc t = f un ct > > > d ir ( E m p ty ) [ ’ _ _ d oc _ _ ’ , ’ _ _ m o du l e __ ’ , ’ f u nc t ’ , ’ v a lu e ’ ] > >> e = E mp ty ( ) > > > e . f u nc t ( ) 1
Quelques attributs notoires __doc__ contient la documentation de la classe, de l’objet, de la fonction, du module, etc. efinition de la classe, de l’ob jet, de __module__ contient le nom du module contenant la d´ la fonction, du module, etc. __name__ contient le nom de la fonction ou de la m´ethode. __file__ contient le nom du fichier contenant le code du module.
3.3 3.3.1
Les objets, version avanc´ ee Un peu de r´ eflexion
Les techniques de r´eflexion permettent de d´ecouvrir (instrospection) et de manipuler dynamiquement et automatiquement les attributs (et fonctions) d’un objet. Ces techniques sont utilisables, par exemple, pour le chargement de code dynamique comme la mise en œuvre d’un m´ecanisme de plug-ins. Elles sont aussi couramment utilis´es dans les environnements de d´eveloppement qui font de la compl´etion automatique (il faut bien aller chercher l’information quelque part). Il existe trois fonctions de base en Python : – hasattr() test si un attribut existe, – getattr() donne acc`es a` la valeur d’un attribut, – setattr() fixe la valeur d’un attribut (avec cr´eation si l’attribut est inexistant). Dans l’exemple suivant, nous manipulons l’instance ´etendue de la classe Empty : apr`es avoir test´e son existence, nous r´ecup´erons dynamiquement la m´ethode nomm´ee funct pour en demander ensuite l’ex´ecution. Enfin, nous d´efinissons un nouvel attribut name dont la valeur est fix´ee a` myempty. c 2003-2007, Rapha¨el Marvie
50
Plongeon dans les objets
> > > h a sa t t r ( e , ’ f u nc t ’ ) 1 > >> f = g et at tr ( e , ’ f un ct ’ ) > >> f < f u n ct i on f u nc t a t 0 x 8 1b 73 3 4 > > >> f ( e) 2 > > > s e ta t t r ( e , ’ n a me ’ , ’ m y e mp t y ’ ) > > > e . n a me ’myempty’
3.3.2
Un peu plus de r´ eflexion avec inspect
Le module inspect offre des moyens suppl´ementaires pour l’introspection, par exemple d´ecouvrir ce que contient une classe, un objet ou un module. L’exemple suivant r´ecup`ere les membres de la classe E puis les membres d’une instance de cette classe. Pour chaque membre de l’objet (classe ou instance), un tuple est fourni contenant le nom de l’attribut et sa valeur. Nous pouvons constater que la diff´erence se limite a` l’´etat de la fonction f : non li´ee dans le cas de la classe, donc que l’on ne peut ex´ecuter directement, et li´ee a` l’instance dans le cas de l’objet que l’on peut donc ex´ecuter directement apr`es un getattr. > >> c la ss E : ... def f ( self ): ... return ’ hello ’ ... >>> e = E() > > > i m po r t i n sp e ct > > > i n sp e c t . g e t me m b er s ( E ) [ ( ’ _ _ do c __ ’ , N on e ) , ( ’ _ _ m o du l e __ ’ , ’ _ _ m ai n __ ’ ) , ( ’ f ’, < u nb ou nd m et ho d E . f >) ] > > > i n sp e c t . g e t me m b er s ( e ) [ ( ’ _ _ do c __ ’ , N on e ) , ( ’ _ _ m o du l e __ ’ , ’ _ _ m ai n __ ’ ) , ( ’ f ’, < b ou nd m et ho d E . f o f < _ _ ma in __ . E i ns ta nc e a t 0 x 82 5e c5 4 > > )]
Ce module permet aussi de savoir ce que l’on est en train de manipuler : quel est le type d’un objet (classe, instance, attribut). La fonction ismethod() permet de savoir si un objet donn´e est, ou non, une m´ethode (li´ee ou non). >>> 1 > >> >>> 0 >>> 1 > >>
i n sp e c t . i s cl a ss ( E ) f = g et at tr ( e , ’ f’ ) i n sp e c t . i s f un c t io n ( f ) i n sp e c t . i s me t ho d ( f ) F = g et at tr ( E , ’ f’ )
c 2003-2007, Rapha¨el Marvie
3.3 Les objets, version avanc´ ee
51
> > > i n sp e c t . i s me t ho d ( F ) 1
L’association de l’introspection de base et du module inspect permet d’automatiser l’utilisation des m´ethodes d’une instance : invocation g´en´erique d’une m´ethode r´ecup´er´ee dynamiquement apr`es contrˆole que c’est bien une m´ethode. L’exemple suivant montre aussi les deux mani`eres d’invoquer une m´ethode, et la signification du self : a.foo() est en fait traduit en A.foo(a) par l’interpr´eteur (consid´erant que a est une instance de la classe A). > >> f1 = g et at tr ( e , ’ f ’) > >> f2 = g et at tr ( E , ’ f ’) > > > i f i n sp e ct . i s m e t ho d ( f 1 ) : ... f1 () # ‘ f1 ’ est liee a ‘e ’ ... ’hello’ > > > i f i n sp e ct . i s m e t ho d ( f 2 ) : ... f2 ( e ) # ‘ f2 ’ n ’ es t p as l iee , a rg um en t 1 = = s el f ... ’hello’
Le module inspect permet mˆeme d’acc´eder dynamiquement au code source d’un objet. Toutefois, cela n’est pas valable pour le code saisi en interactif (ce qui est somme toute normale vu qu’il n’est pas stock´e dans un fichier). > >> f ro m e xa m pl es i mp or t C on fl i ct
getfile() donne le nom du fichier de d´ efinition de l’objet (TypeError si cette op´eration
est impossible). > > > i n s p e ct . g e t f i le ( C o n f l i ct ) ’examples.py’
getmodule() donne le nom du module d´ efinissant l’objet (sans garantie par exemple dans
le cas du code dynamiquement cr´e´e). > > > i n s p e ct . g e t m o d u le ( C o n f l i ct ) < m o du l e ’ e x a mp l e s ’ f r om ’ e x a mp l e s . py ’ >
getdoc() retourne la documentation de l’objet. > > > i n sp e ct . g e t d oc ( C o n f l ic t ) ’ I l lu st r at i on d e c on fl it a tt ri b ut / m et ho de ’
getcomments() retourne la ligne de commentaire pr´ec´edant la d´efinition de l’objet.
efinissant getsourcelines() donne un tuple contenant la liste des lignes de code source d´ l’objet pass´e en param`etre et la ligne du d´ebut de la d´efinition dans le fichier. > > > l in es , n um = i n sp e ct . g e t s o u r ce l i n es ( C o n f l ic t ) >>> for l in lines : print num , l , ; num += 1 ...
c 2003-2007, Rapha¨el Marvie
52
Plongeon dans les objets 3 4 c l as s C o nf l i ct : 35 ’ ’’ Il lu st ra ti on de co nf li t a tt ri bu t / m et ho de ’ ’’ 36 def __i nit__ (self ): 37 self . name = ’ Conflic t ’ 38 def name (self ): 39 return ’ You will never get this string !’
getsource() est similaire ` a la pr´ec´edente, mais retourne uniquement le code de la d´efinition
sous la forme d’une chaˆıne de caract`eres.
3.4 3.4.1
Les exceptions en python D´ efinition et lancement
Les exceptions sont des objets comme les autres, donc d´efinies par des classes comme les autres (ou presque). Elles sont simplement un penchant pour ne rien faire (les classes d’exception contiennent rarement des traitements). La d´efinition minimale d’une classe pour une exception revient a` ´etendre la classe de base Exception. > > > c l as s M o n Er r e ur ( E x c e p t io n ) : ... pass ...
La mot-cl´e raise permet de lever une exception (d´efinie par l’usager ou standard). Si l’on souhaite associ´e de l’information a` une exception, il suffit de faire suivre le type de l’exception d’un message (s´epar´e par une virgule). 3 > > > r a is e M o n Er r e ur T r ac eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 1 , in ? __main__.MonErreur > > > r a is e M o n Er r e ur ( ) T r ac eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 1 , in ? __main__.MonErreur > > > r a is e N a me E rr o r , ’ c e la c o in c e ’ T r ac eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 1 , in ? N a m eE r r or : c e la c o in c e
Une exception peut aussi contenir des attributs et m´ethodes (en g´en´eral pour fournir de l’information). Ici, la m´ethode standard __str__ (traduction de l’objet en chaˆıne) et utilis´ee pour acc´eder facilement a` la valeur contenue dans l’exception (par d´efaut le m´ecanisme 3
Les exceptions sont lev´ ees comme des objets. Une classe est d´efinie par un objet dans l’interpr´eteur. Donc la d´efinition de la classe peut ˆetre lev´ee comme une exception. Ce qui n’est pas si choquant pour les cas simple (exception avec message d’erreur).
c 2003-2007, Rapha¨el Marvie
3.4 Les exceptions en python
53
d’exception appelle cette m´ethode). Pour fournir de l’information a` une exception, il suffit de l’instancier en passant des param`etres au constructeur lors de l’utilisation de raise. > > > c l as s M o n Er r e ur T o o ( E x c ep t io n ) : ... def __ init__ ( self , val = None ): ... self . _value = val ... def __str__ ( self ): ... return str ( self . _value ) ... > > > r a is e M o n Er r e ur T o o ( 1 2) T r ac eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 1 , in ? _ _ m a i n __ . M o n E r r e u r T oo : 1 2
3.4.2
Traitement des exceptions
Il y a deux approches pour le traitement des exceptions en Python dont le choix d´epend des besoins : – quoi faire en cas de probl`eme, – que faut il toujours faire mˆeme s’il y a un probl`eme.
3.4.2.1
try ... except
Gestion des probl`emes, le try ... except permet en cas de lev´ee d’exception, de pouvoir tenter de traiter le probl`eme. La clause else est optionnelle est permet de faire un traitement si tout s’est bien pass´e. Il peut y avoir plusieurs clauses except pour traiter diff´erents cas exceptionnels. try: ( e x c e p t < e x c e pt i o n > : < i n s t r u c t i o n s t r a i t e m e nt e x c ep t i on > ) + [else: < i n st r uc t io n s i d ´ e r o u l e m e nt c o rr e c t > ]
L’identification d’une peut prendre plusieurs formes : – ExceptionType est utile lorsque seul le type de l’exception est important, par exemple parce qu’elle ne contient pas d’information ; – ExceptionType, variable permet de r´ecup´erer l’exception du type sp´ecifi´e dans variable et donc d’epxloiter les donn´ees et traitements de l’exception ; – (ExceptionType1, ExceptionType2, ...) permet de prendre en compte un ensemble d’exception car le traitement de cas particulier est mutualisable.
Exemple 1 Lecture d’un fichier texte : on ne lit le fichier que si l’ouverture s’est bien pass´ee. On utilise la clause else pour le code qui ne doit ˆetre fait que si aucune exception n’est lev´ee. Cela permet d’isoler l’appel qui pose potentiellement probl`eme c 2003-2007, Rapha¨el Marvie
54
Plongeon dans les objets dans le bloc try (et non de mettre tout le code dans ce bloc sans savoir ensuite qui a vraiment pos´e probl`eme). > >> t ry : ... f = open (’/ tmp /bar .txt ’) . .. e x ce p t I OE r ro r , e : ... print e . .. e l se : ... for line in f . readl ines (): ... print line , ... f . close () ... h e ll o w o rl d ! b on jo ur l e m on de !
Exemple 2 Gestion de plusieurs exceptions : l’affichage va d´ependre de l’exception qui est lev´ee (elle mˆeme lev´ee de mani`ere al´eatoire). Une chaˆıne ´etant un objet, elle peut ˆetre utilis´ee comme exception. Cette mani`ere de faire est toutefois a` proscrire. > >> t ry : ... if int (random . random () * 100) % 2: ... raise ’ impair ’ ... else : ... raise ’ pair ’ . .. e x ce p t ’ p a ir ’ : ... print " c ’est un nombre pair " . .. e x ce p t ’ i m p ai r ’ : ... print " c ’est un nombre pair " ... c ’ es t u n n om br e p ai r
3.4.2.2
try ... finally
Quoi qu’il arrive, le try ... finally permet de faire un traitement mˆ eme si une exception a ´et´e lev´ee. Le bloc finally est ´evalu´e avant un return contenu dans le bloc try et ce qu’il y ait ou non eu une exception de lev´e. Attention : Un return dans le finally masque un return dans le try. try: finally:
Attention : Dans ce cas, on ne sait pas ce qui s’est mal pass´ e. Il n’y a pas moyen de faire de gestion d’erreur dans le finally qui laisse filer les exceptions. ( (
) )
> >> t ry : ... raise K ey boa rd Int err upt
c 2003-2007, Rapha¨el Marvie
3.5 Toujours ` a propos des objets
55
. .. f i na l l y : ... print ’ki C ki A ta P < ctrl -C > ? ’ ... ki C ki A ta P < ctrl - C> ? T r ac eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 2 , in ? KeyboardInterrupt
Il n’est pas possible de composer les deux formes dans un seul bloc, l’utilisation imbriqu´ee des deux formes est donc parfois n´ecessaire.
3.4.3
Traitement d’exceptions et h´ eritage
Petit probl`eme courant, attention a` l’ordonnancement des except ! Il faut toujours, dans le cas o` u les exceptions sont d´efinies par une relation d’h´ eritage, commencer par traiter les exceptions les plus sp´ecifiques. Dans le cas contraire, la gestion des exceptions les plus g´en´erales masque les traitements relatifs aux exceptions les plus sp´ecifiques qui ne sont jamais utilis´es. c l as s A ( E x c e pt i o n ) : p as s c la ss B ( A ): p as s > >> for x in [ A, B ]: ... try : raise x ... except B : print ... except A : print A B > >> for x in [ A, B ]: ... try : raise x ... except A : print ... except B : print A A
3.5
’B ’ , ’A ’ ,
’A ’ , ’B ’ ,
Toujours a ` propos des objets
Cette section est pour certain aspects plutˆ ot a` lire une fois familier avec Python.
3.5.1
Unification des types et des classes
Depuis Python 2.2, les types et les classes ont ´et´e unifi´es en Python. C’est-`a-dire qu”il n’y a plus de diff´erence fondamentale entre les types de base et les classes d´efinies par l’utilisateur. Le b´en´efice de cette unification est qu’il est d´esormais possible de d´efinir des classes h´eritant des types de base. c 2003-2007, Rapha¨el Marvie
56
Plongeon dans les objets
Suite a` cette unification, et pour ne pas briser la compatibilit´e avec les programmes existants, la d´eclaration des classe a un peu ´evolu´ e (ce que nous avons vu jusqu’ici est toujours valable). Pour pr´eciser qu’une classe est d´efinie avec la nouvelle forme, il faut la faire h´eriter de object, d’un type de base ou d’une classe h´eritant de object). Attention, les classes de la librairie standard ne suivent pas toute la nouvelle forme et sont donc consid´er´ees comme diff´erentes . L’exemple suivant pr´esente les deux formes de d´eclaration de classes simultan´ement. L’utilisation de la fonction type sur des instances de ces deux classes illustre bien la diff´erence de statut vis-`a-vis de l’interpr´eteur (lignes 9-12). ( (
) )
> >> c la ss F oo : ... pass ... > > > c l as s B ar ( o b j e ct ) : ... pass ... > >> f = Foo () > >> b = Bar () > > > t y pe ( f ) < t y pe ’ i n s ta n ce ’ > > > > t y pe ( b ) < c l as s ’ _ _ m ai n __ . B a r ’ >
Avec cette nouvelle forme, l’utilisation de m´ethodes fournies par les super-classes est aussi modifi´ee. Lors de la red´efinition d’une m´ethode dans une sous-classe, la fonction efinition (originale) de cette m´ethode dans la super-classe super permet d’acc´eder a` la d´ (ou une des super-classes). La fonction super prend comme premier param`etre le type a` partir duquel doit se faire la recherche4 et comme second param`etre self (ligne 8 de l’exemple suivant). Contrairement a` l’ancienne forme, il n’est plus n´ecessaire de passer self en premier argument de la m´ethode (voir la section 3.1.4). La fonction super est aussi utilisable dans la d´efinition des constructeurs. > > > c l as s F oo ( o b j e ct ) : ... def foo ( self ): ... print ’ Foo . foo ’ ... > > > c l as s F o oT o o ( F oo ) : ... def foo ( self ): ... print ’ FooToo . foo ’ ... super ( FooToo , self ). foo () ... > >> f2 = F oo To o () 4
Dans le cas d’une hi´erarchie `a plusieurs niveaux, la recherche de la m´ethode h´erit´e ne se fait pas n´ecessairement `a partir de la super-classe, mais elle peut se faire `a partir de la super-super-classe par exemple.
c 2003-2007, Rapha¨el Marvie
3.5 Toujours ` a propos des objets
57
> > > f 2 . f oo ( ) FooToo.foo Foo.foo
3.5.2
D´ efinition de propri´ et´es
Avec l’unification classe / type, la notion de propri´et´e est apparue en Python. Une propri´et´e permet de manipuler un attribut a` l’aide d’accesseurs de mani`ere transparente (c’est-`a-dire que l’on ne dit pas explicitement que l’on utilise les accesseurs). Une propri´et´e est d´efinie a` l’aide de la fonction property dans le contexte d’une classe qui ´etend (mˆeme indirectement) object. La fonction property prend en param` etre la fonction pour la lecture, la fonction pour l’´ecriture, la fonction pour la suppression de la valeur associ´ee et une chaˆıne de documentation. Tous les param`etres sont optionnels (eh oui, il est mˆeme possible de d´efinir une propri´et´e ne fait rien, mˆeme pas ˆetre lue). Dans l’exemple suivant, la classe A est d´efinie avec une propri´et´e value en lecture et ´ecriture : elle est d´efinie avec une m´ethode pour la lecture et une pour l’´ecriture. La classe ` elle d´efinie avec une propri´et´e value en lecture seule : seule une m´ethode de B est quant a lecture est fournie. > > > c l as s A ( o b j ec t ) : ... def _ _init_ _( self , val =0): ... self . _value = val ... def get_ value ( self ): ... return self . _value ... def set_ value ( self , val ): ... self . _value = val ... va lue = pr op er ty ( get _v alu e , se t_ va lu e ) ... > > > c l as s B ( o b j ec t ) : ... def _ _init_ _ ( self ): ... self . _value = 0 ... def get_ value ( self ): ... return self . _value ... v alu e = p ro pe rt y( g et _v al ue ) ...
Une propri´et´e est utilis´e comme un attribut. Dans le cas courant l’utilisation est peu diff´erente d’un attribut classique, mˆeme les m´ethode de lecture / ´ecriture pourrait tr`es bien aller chercher l’information dans un fichier ou autre. Enfin, la tentative d’´ecriture de la propri´et´e value sur une instance de B se solde par une exception. Il est donc int´ eressant d’utiliser des propri´et´es pour faire du contrˆ ole d’acc`es sur des attributs. >>> a = A (1) > > > a . v a lu e 1
c 2003-2007, Rapha¨el Marvie
58
Plongeon dans les objets > >> a . va lu e = 2 > > > a . v a lu e 2 >>> b = B (2) > > > b . v a lu e 2 > >> b . va lu e = 1 T r ac eb a ck ( m os t r ec en t c al l l as t ): F il e " < st di n > " , l in e 1 , in ? A t t ri b u te E r ro r : c an ’ t s et a t t ri b u te
3.5.3
D´ ecorateurs
Le concept de d´ecorateur de fonction (ou de m´ethode) a ´et´e introduit dans la version 2.4 (PEP 318). La notion de d´ecorateur n’est pas des plus simple a` expliquer, mais on peut la voire comme une fonction qui applique des traitements sur une autre fonction pour en changer le comportement. Un d´ecorateur peut donc ˆetre toute fonction prenant en argument une fonction (ou tout objet appelable). L’utilisation d’une fonction comme d´ecorateur d’une autre fonction se fait en utilisant le nouvel op´erateur @. Consid´erant un d´ecorateur decorateur et une fonction foo les deux d´eclarations suivantes sont ´equivalentes. @decorateur d ef f oo ( ) : pass d ef f oo ( ) : pass f oo = d e c or a t eu r ( f o o )
L’exemple suivant prend le grand classique de la trace des appel de fonction pour illustrer la d´efinition et l’utilisation d’un d´ecorateur. La fonction trace d´efinie une fonction d’emballage (un wrapper) _trace qui va, en plus du comportement normal de la fonction qu’elle emballe, afficher le nom et les arguments de celle-ci. L’utilisation de trace permet donc de substituer la d´efinition de base d’une fonction par une version incluant la trace : trace retourne tout simplement une fonction. Notre fonction trace va ˆetre utilisable sur toute fonction comme un d´ecorateur pour afficher sur la sortie standard les appels a` cette fonction. Ici, nous tra¸cons la fonction bar, dont la d´efinition est tout ce qu’il y a de plus normal, si ce n’est la d´eclaration @trace. > > > d ef t r ac e ( f c t ): ... def _trace (* args ): ... print ’ < % s % s > ’ % ( fct . __name__ , args ) ... return fct ( args ) ... return _trace ... > > > @ t ra c e
c 2003-2007, Rapha¨el Marvie
3.6 Exercices
59
. .. d ef b ar ( n a m e ): ... print ’ hello % s ’ % name ... > > > b ar ( ’ r a fi ’ ) < b ar ( ’ r af i ’ ,) > h e ll o r a fi
Il est `a noter que les d´ecorateurs sont tr`es pratiques dans le cas des classes pour, par exemple d´efinir des m´ethodes comme des m´ethodes de classe, des m´ethodes statiques ou bien synchronis´ees (dans la cas de la programmation multi-thread)5 . Une fonction (ou m´ethode) peut ˆetre d´ecor´ee plusieurs fois.
3.6 3.6.1
Exercices Premi` eres classes
– Implanter des classes Pile et File utilisant les liste comme structure de donn´ ees interne et respectant l’interface suivante (utiliser l’h´eritage). c l as s B as e : d ef p op ( s e l f ) : pass d ef p u sh ( s e lf , e lt ) : pass
– Reprendre l’exercice 2.4.2 en implantant les fonctionnalit´es au sein d’une classe.
3.6.2
Design pattern ´ etat
– L’´etat d’un objet a de type A est implant´e par plusieurs classes. L’instance de ces classes qui repr´esente l’´etat de l’objet varie au cours du cycle de vie de l’objet. Les m´ethodes de l’objet sont d´el´egu´ees a` l’instance repr´esentant l’´etat a` un moment donn´e. – Implanter ce design pattern pour repr´esenter un feu tricolore (une classe d’´etat par couleur, une m´ethode pour changer la couleur du feu et une m´ethode qui donne le droit de passage).
5
NpA : Ajouter une section sur ces trois types de m´ ethodes et une section sur la programmation multi-thread en Python.
c 2003-2007, Rapha¨el Marvie
60
Plongeon dans les objets
c 2003-2007, Rapha¨el Marvie
Chapitre 4 Python et XML 4.1 4.1.1
XML, avec une vision DOM Langages de balises
– Au commencement ´etait SGML – Standard Generalized Markup Language – Simplifi´e a` outrance avec HTML pour le Web – Transform´e en produit marketing avec XML – Python supporte toute la petite famille – HTML, XHTML et SGML pour HTML – XML, DOM et SAX
4.1.2
XML, quels outils ?
Il existe plusieurs librairies pour manipuler des documents XMl avec Python, mais ce chapitre se limite `a une partie du package standard xml. Ce package fournit plusieurs sous-packages : – dom contient minidom, une impl´ementation de DOM en Python, – sax est un dictionnaire des impl´ementation disponibles, – parsers contient les parsers utilis´es en interne par DOM et SAX. En compl´ements, plusieurs librairies et extensions sont disponibles. Elles fournissent, par exemple, des abstractions de plus haut niveau et des outils typ´es par rapport a` une utilisation donn´ee.
4.1.3
DOM, petit rappel
Pour ce qui est de la manipulation d’un fichier XML, nous allons uniquement utiliser DOM (Document Object Model). DOM propose de manipuler un document XML en 61
62
Python et XML
m´emoire comme un arbre d’objets repr´ esentant les noeuds du document. Les interfaces standard DOM sont les suivantes. Interface Node NodeList Document Element Attr Comment Text
4.1.4
Repr´ esentation de Interface de base des noeuds S´ equence de noeuds Repr´esente un document complet El´ement de la hi´erarchie Noeud repr´esentant un attribut d’un noeud Noeud repr´entant un commentaire Noeud de donn´ees textuelles
Exemple du chapitre
Le listing suivant pr´esente un exemple de document XML utilis´e dans la suite du chapitre pour illustrer la manipulation de tels documents. < ? xm l v e rs i on = " 1 . 0 " ? > < c o n ta c t n am e = " d oe " f i rs t n am e = " j o hn " > < r oa d v al ue = " 10 , b in ar y s tr ee t " / > < p o st a l v a lu e = " 0 0 01 " / > < c i ty v a lu e = " c pu " / > < p r o gr a m mi n g l a ng = " a s m " / > < c o n ta c t n am e = " d u po n t " f i r st n a me = " j e a n " > < r oa d v al ue = " i mp as se d e l ’ a ss e mb l eu r " / > < p o st a l v a lu e = " 0 1 00 " / > < c i ty v a lu e = " d r am " / > < p r o gr a m mi n g l a ng = " c " / > < c o n ta c t n am e = " t e r pr e t te " f i r st n a me = " q u e n t in " > < r oa d v al ue = " a ve nu e d u s cr ip t " / > < p o st a l v a lu e = " 1 0 01 " / > < c it y v al ue = " s al t s na ke c it y " / > < p r o gr a m mi n g l a ng = " p y t h on " / >
c 2003-2007, Rapha¨el Marvie
4.2 Naviguer dans un arbre DOM
4.2
63
Naviguer dans un arbre DOM
4.2.1
minidom il fait le maximum ( (
) )
Le module minidom est une mise en œuvre de DOM pour Python. Il fournit toutes les interfaces de base DOM et un parser de fichier (ou de chaˆıne) XML. Il est disponible en standard dans l’environnement (librairie PyXML).
4.2.2
Parser un document XML
La fonction minidom.parse permet d’analyser un fichier XML et d’obtenir un arbre DOM correspondant. Elle retourne un objet de type Document. En une ligne, elle est pas belle la vie ? > >> f ro m x ml . d om i mp or t m in id om > > > d oc = m i ni d om . p a r s e ( ’ / tm p / c o n ta c ts . x m l ’ ) > >> d oc < x ml . d o m . m i ni d om . D o c u m en t i n st a n ce a t 0 x 8 27 f b9 c >
4.2.3
Parcourir un arbre DOM
Un certain nombre d’op´erations et d’attributs disponibles sur tous les ´el´ements d’un arbre DOM pour en permettre son parcours. hasChildNodes() indique si un noeud a des fils. > > > d oc . h a s C h i ld N o de s ( ) 1
childNodes donne acc` es aux fils d’un noeud (sous la forme d’une liste). > > > d oc . c h i l d No d e s [ < D OM E l e me n t : c o nt a ct s a t 1 3 77 6 36 7 6 > ] > > > d o c . c h i l d N o d e s [ 0 ] . h a s C h i l d N o de s 1
documentElement fournit le noeud racine d’un document DOM. > > > r o ot = d oc . d o c u m e nt E l em e n t
firstChild, lastChild donnent acc`es respectivement au premier et au dernier fils d’un
noeud. > > > r o o t . c h i l d N o d es [ < DO M T ex t n od e " \ n " > , < D OM E le me nt : c on ta ct at 1 37 75 76 92 > , < DO M T ex t n od e " \n " > , < D OM E le me nt : c on ta ct at 1 37 43 76 76 > , < DO M T ex t n od e " \n " > , < D OM E le me nt : c on ta ct at 1 36 72 33 16 > , < D OM T ex t n od e " \ n " >]
c 2003-2007, Rapha¨el Marvie
64
Python et XML > > > r o o t . f i r s t C h i ld < DOM Text node " \ n " > > > > r o ot . l a s t C hi l d < D OM T ex t n od e " \ n" >
es au fils suivant et au fils nextSibling, previousSibling donnent respectivement acc` pr´ec´edent (ou None si plus de fils). Le calcul se fait par rapport a` une racine commune. > > > c u rr e nt = r oo t . f i r s tC h i ld > > > w h il e c u rr e nt : ... print current , ... current = current . ne xt Sib li ng ... < DO M T ex t n od e " " > < D OM E le me nt : c on ta ct a t 1 37 75 76 92 > < D OM T ex t n od e " " > < D OM E le me nt : c on ta ct a t 1 37 43 76 76 > < D OM T ex t n od e " " > < D OM E le me nt : c on ta ct a t 1 36 72 33 16 > < D OM T ex t n od e " ">
parentNode donne acc` es au parent (direct) d’un noeud. > > > r o ot < D OM E le me nt : c o nt ac ts a t 1 37 76 36 76 > > > > r o o t . f i r s t C h i ld < DOM Text node " \ n " > > > > r o o t . f i r s t C h i l d . p a r e n t N o de < D OM E le me nt : c o nt ac ts a t 1 37 76 36 76 >
e, isSameNode() permet de tester si deux noeuds sont ´egaux (´egalit´e au sens de l’identit´ parle-t-on de la mˆeme personne). > > > r oo t . f i r s t C h i l d . i s S a m e N o de ( r o o t . l a s t C h i l d ) 0 >>> root.firstChild.isSameNode(root.childNodes[0]) 1
4.2.4
Recherche dans un arbre DOM
La recherche dans un arbre DOM se fait principalement par nom de tag (nom de noeud). La fonction getElementsByTagName(), disponible sur les noeuds de type Document et Element, donne tous les fils (et sous -fils) portant le nom de tag fourni. n
> > > r o ot . g e t E l e m e n t s B y T a g N am e ( ’ c o n t a c t ’ ) [ < D OM E l em e nt : c o nt a ct a t 1 3 77 57 6 92 > , < D OM E l em e nt : c o nt a ct a t 1 3 74 37 6 76 > , < D OM E l em e nt : c o nt a ct a t 1 3 67 2 33 1 6 > ] > > > r o ot . g e t E l e m e n t s B y T a g N am e ( ’ p r o g r a m m i n g ’ ) [ < D OM E l em e nt : p r o gr a m mi n g a t 1 37 7 88 49 2 > ,
c 2003-2007, Rapha¨el Marvie
4.3 Acc´ eder aux informations d’un noeud
65
< D OM E l em e nt : p r o gr a m mi n g a t 1 37 7 55 69 2 > , < D OM E l em e nt : p r o gr a m mi n g a t 1 3 76 0 21 4 0 > ]
4.2.5
NodeList et objets s´ equences
Le r´esultat retourn´e par les fonctions childNodes et getElementsByTagName est de type NodeList et se comporte comme une s´equence classique . ( (
) )
Pour se comporter comme une s´equence, un objet doit offrir (au minimum) les m´ethodes suivantes : – __len__() et __getitem__(i) pour l’acc`es aux ´el´ements (boucle for), – __setitem__(i) et __delitem__(i) pour les s´equences modifiables.
4.3
Acc´ eder aux informations d’un noeud
4.3.1
Informations li´ ees au noeud
esentant le type du noeud : nodeType donne une constante (1-10) repr´ ELEMENT_NODE, ATTRIBUTE_NODE, TEXT_NODE, CDATA_SECTION_NODE, ENTITY_NODE, PROCESSING_INSTRUCTION_NODE, COMMENT_NODE, DOCUMENT_NODE, DOCUMENT_TYPE_NODE, NOTATION_NODE. > > > r o ot . n o d e T yp e = = m i ni d om . N o d e . E L E M EN T _ NO D E 1 > > > r o ot . f i r s t Ch i l d . n o d eT y pe = = m i ni d o m . N od e . E L E M EN T _ NO D E 0 > > > r o ot . f i r s t Ch i l d . n o d eT y pe = = m i ni d o m . N od e . T E X T _N O D E 1
nodeName donne le nom du nœud (tag de la balise). Attention, le comportement est
variable selon les noeuds : pour un ´el´ ement ce sera le nom de la balise XML, pour un noeud repr´esentant du texte, ce sera #text > > > r o ot . n o d e N am e u’contacts’ > > > r o o t . f i r s t C h i l d . n o d e N a me ’#text’
nodeValue donne la valeur du nœud (contenu). Attention, le comportement est variable selon les noeuds : pour un ´el´ement ce sera None pour un noeuds contenant de l’in-
formation ce sera cette information. Pour les noeuds contenant du texte, il est aussi possible d’utiliser l’attribut data. > > > r o ot . n o d e V al u e > > > r o o t . f i r s t C h i l d . n o d e V a l ue u ’\ n ’
c 2003-2007, Rapha¨el Marvie
66
Python et XML >>> root.firstChild.data u ’\ n ’
4.3.2
Informations li´ ees aux attributs d’un noeud
esence d’attributs dans un noeud. hasAttributes() teste la pr´ > > > r o ot . h a s A t t ri b u te s ( ) 0 >>> root.childNodes[1].hasAttributes() 1
attributes fourni les attributs du noeud (objet du type NamedNodeMap ou None). > > > r o o t . f i r s t C h i l d . a t t r i b u t es > > > r o o t . c h i l d N o d e s [ 1 ] . a t t r i b u te s < x ml . d o m . m i ni d om . N a m e d N od e M ap o b je c t a t 0 x 8 1b 2 98 c >
getAttribute() retourne la valeur d’un attribut comme une chaˆıne. > >> c = r oo t . c hi l dN o de s [ 1] > > > p r in t c . g e t A tt r i bu t e ( ’ n a me ’ ) doe
getAttributeNode() retourne la valeur d’un attribut comme un objet de type Attr. > > > p r in t c . g e t A t tr i b u te N o d e ( ’ n am e ’ ) < x ml . d o m . m i ni d om . A t t r i n s ta n ce a t 0 x 8 36 0 42 4 >
Une NamedNodeMap se comporte comme un dictionnaire. La m´ethode item() permet d’acc´eder aux couples nom d’attribut / valeur textuelle d’attribut, la m´ethode keys() donne acc`es aux noms des attributs et la m´ethode values() donne acc`es a` la liste des objets Attr repr´esentant les attributs. > > > a tt r . i t e ms ( ) [ ( u ’ n am e ’ , u ’ d oe ’ ) , ( u ’ f i r st n am e ’ , u ’ j o hn ’ ) ] > > > a tt r . k e ys ( ) [ u ’ n am e ’ , u ’ f i r st n a me ’ ] > > > a tt r . v a l ue s ( ) [ < x ml . d o m . m i ni d om . A t t r i n st a n ce a t 0 x 3 02 f fd 2 8 > , < x m l . d o m . m i n i d o m . A t t r i n s t a n ce a t 0 x 3 0 2 f fd 7 8 > ] > >> f or a i n a tt r . v al ue s ( ): . .. p ri nt a . n od eT yp e , a . no de Na me , a . no de Va lu e ... 2 n am e d oe 2 f i rs t na me j oh n
En plus des m´ethodes classiques sur les dictionnaires, il existe deux m´ethodes pour manipuler les NamedNodeMap : c 2003-2007, Rapha¨el Marvie
4.4 Construire un document XML
67
– length donne la longueur de la map d’attributs, – item(i) donne le i-eme ´el´ement (de type Attr) de la map ou None. > > > a t tr s = r oo t . c h i l dN o d es [ 1 ] . a t t r ib u t es > >> f or i dx i n r an ge ( 0 , a tt rs . l e ng th ) : ... a = attrs .item (idx ) ... print ’( ’ + a . name + ’) ’ , . .. p ri nt a . n od eT yp e , a . no de Na me , a . no de Va lu e ... ( n am e ) 2 n am e d oe ( f i rs tn a me ) 2 f ir s tn am e j oh n
4.4
Construire un document XML
4.4.1
Cr´ eer un arbre DOM
La cr´eation d’un document (de son arbre DOM) se fait par instanciation de la classe ethodes pour fabriDocument (c’est un objet comme un autre). Cette classe fournit des m´ quer les noeuds. A la cr´eation, un document ne contient rien, pas mˆeme de noeud racine. > > > n e wd o c = m i ni d o m . D o cu m en t ( ) > > > n e wd o c < x ml . d o m . m i ni d om . D o c u m en t i n st a n ce a t 0 x 8 27 f e7 c > > > > n e w d o c . d o c u m e n t E l e m en t >>>
4.4.2
Cr´ eer des noeuds DOM
Les m´ethodes de cr´eation de noeud n’incluent pas l’ajout de l’´el´ement cr´e´e dans l’arbre. Ici, nous allons cr´eer un document excessivement simple : – une racine root avec un attribut name, – un commentaire, – un noeud de texte contenu dans un noeud sometext. createElement(tag) cr´ee un nouvel ´el´ement (de type Element) avec le nom de tag pass´e
en param`etre et le retourne. > > > n e wr o ot = n e wd o c . c r e a te E l em e n t ( ’ r oo t ’ )
createAttribute(name) cr´ee un noeud de type Attr avec le nom name. Une fois le noeud cr´e´e, la valeur peut ˆetre fix´ee avec l’attribut nodeValue. > > > r o o ta t tr = n e wd o c . c r e a te A t tr i b ut e ( ’ n a m e ’ ) > >> r o ot at tr . n o d eV a lu e = ’ f oo ’
createTextNode(data) cr´ee un noeud de donn´ee contenant le text pass´e en param`etre (`a inclure dans un noeud englobant, ici le noeud sometext cr´e´e pour).
c 2003-2007, Rapha¨el Marvie
68
Python et XML > > > t e x tn o de = n e wd o c . c r e a te E l em e n t ( ’ s o me t e xt ’ ) > > > t e xt = n e wd o c . c r e a te T e xt N o de ( ’ t h i s n od e \ n c o n ta i n s t e xt ’ ) > > > t e x t n o de . a p p e n d C h il d ( t e x t )
createComment(text) cr´ ee un noeud de commentaires contenant le text pass´e en pa-
ram`etre. > > > c o mm e nt = n e wd o c . c r e a te C o mm e n t ( ’ a v e ry u s ef u ll c o mm e nt ’ )
4.4.3
Ajout de noeuds dans un arbre
Les m´ethodes d’ajout dans un arbre viennent en compl´ement des m´ethodes de cr´eation. Leur dissociation est due aux multiples usages que l’on peut faire d’un noeud. Il est possible de construire un document XML partir d’un document existant, dans ce cas on ne va pas recr´eer tout les noeuds, mais peut ˆetre simplement les r´eorganiser. appendChild(new) ajoute un ´el´ement a` la fin de la liste des fils d’un noeud. > > > n e w d oc . a p p e n d C h i ld ( n e w r o o t ) < D OM E le me nt : r oo t a t 1 37 79 74 76 > > > > t e x t n o de . a p p e n d C h il d ( t e x t ) < D OM T ex t n od e " t hi s n od e c...">
insertBefore(new, old) ajoute un ´el´ement avant un fils donn´e d’un noeud. > > > n e w r o ot . i n s e r t B e f o re ( c o mm e n t , t e x t n o de ) < D OM C om me nt n od e " a v er y u se . . . " >
replaceChild(new, old) remplace un ´el´ement fils d’un noeud par un autre ´el´ement. setAttribute(name, value) cr´ ee un nouvel attribut sur un noeud sans passer par une instance de type Attr. > > > n e wr o ot . s e t A t t r ib u t e ( ’ u s ef u ll ’ , ’ n op ’ )
er´e. setAttributeNode(new) ajoute un noeud attribut au noeud consid´ > > > n e w r oo t . s e t A t t r i b u t e No d e ( r o o t a t tr )
4.4.4
Supprimer des noeuds d’un arbre DOM
Il est aussi possible de supprimer des noeuds dans un arbre DOM, par exemple pour en cr´eer une nouvelle version plus ´epur´ee ou pour une restructuration d’un document XML. ` utiliser conjointement avec unlink().1 removeChild(old) supprime un fils d’un noeud a 1
retrouver pourquoi
c 2003-2007, Rapha¨el Marvie
4.5 Exercices
69
> >> t ry : ... old = roo t. r em ov eC hi ld ( roo t. f ir st Ch il d ) ... old .unlink () . .. e xc ep t V a lu e Er r or : p ri nt ’ f ai le d ’ ...
removeAttribute(name) supprime un attribut d’un noeud par son nom. > > > r o o t . f i r s t C h i ld < D OM E le me nt : c on ta ct a t 1 37 75 76 92 > > > > r oo t . f i r s t C h i l d . r e m o v e A t t r i bu t e ( ’ f i r s t n a me ’ )
removeAttributeNode(old) supprime un attribut d’un noeud par la r´ ef´erence de l’objet Attr le repr´esentant ou l`eve l’exception NotFoundErr.
4.4.5
S´ erialiser un document XML
L’objectif de faire un document XML est d’obtenir un fichier. Les fonctions toxml(), ees). toprettyxml() donnent la version texte d’un arbre DOM (une ligne ou multi-ligne indent´ Elles sont disponibles sur tous les noeuds et l’´evaluation est automatiquement r´ecursive. Pour s´erialiser un document, il suffit d’appeler une de ces m´ethodes sur l’objet document. Si l’appel est fait sur un noeud, alors le fichier sera un sous ensemble du document XML. > > > n e wd o c . t o xm l ( ) ’ < ? x ml v e rs i on = " 1 . 0 " ? > \ n < r oo t n a me = " f o o " u s ef u ll = " n o p " > \ < !- - a v e ry u s ef u ll c o mm en t - - > \ < t ex t > t h i s n o de \ n c o n t ai n s t ex t < / t e xt > < / ro ot > ’ > >> o ut pu t = o pe n ( ’/ t mp / t mp . x ml ’ , ’ w ’) >>> output.write(newdoc.toprettyxml()) > > > o u tp u t . c l os e ( )
4.5
Exercices
Le fichier etudiants.xml contient 400 dossiers d’´etudiants (g´en´er´es al´eatoirement) avec la structure d´ecrite ci-dessous. Le but de l’exercice est de produire trois listes sous forme de fichiers XML contenant (par ordre d´ecroissant pour les deux premi`eres) les ´etudiants admissibles, sur liste compl´ementaire ou refus´es. < ? xm l v e rs i on = " 1 . 0 " ? > < e t u di a nt n om = " d o e " p r en o m = " j oh n " d o ss i er = " 0 " > < o r i gi n e u n i ve r s it e = " m i t " / > < f o r ma t io n d i s ci p l in e = " i n f o r ma t i qu e " n i ve a u = " 4 " / > < r e s ul t at s m o ye n ne = " 1 6 " / >
c 2003-2007, Rapha¨el Marvie
70
Python et XML
Pour les trois listes, les informations conserv´ees sont le nom, pr´enom, l’universit´e d’origine et les r´esultats. Les r`egles de selection sont les suivantes. – pour ˆetre admis, un(e) ´etudiant(e) doit avoir un niveau Bac+4, dans une formation en informatique, avec une moyenne sup´erieure a` 12 ; – si sa discipline n’est pas informatique (mais toujours avec les crit` eres de niveau et de moyenne), il (elle) est sur liste compl´ementaire ; – sinon il(elle) est refus´e(e). Il faut pour cela parser le fichier etudiants.xml, naviguer dans l’arbre DOM ainsi produit et construire trois arbres DOM qui seront en fin de traitement s´erialis´es dans les fichiers admissibles.xml, complementaires.xml et refuses.xml. La structure de ces trois fichiers est d´ecrite ci-dessous. < ? xm l v e rs i on = " 1 . 0 " ? > < a d m i s s i b l e s | c o m p l e m e n t a i r e s | r e f u s es > < e t u di a nt n om = " d o e " p r en o m = " j oh n " d o ss i er = " 0 " > < o r i gi n e u n i ve r s it e = " m i t " / > < r e s ul t at s m o ye n ne = " 1 6 " / > < / a d m i s s i b le s | c o m p l e m e n t a i r es | r e fu s e s >
c 2003-2007, Rapha¨el Marvie
Chapitre 5 Python et la persistance de donn´ ees 5.1
Fichiers DBM
5.1.1
Description et utilisation
Le module anydbm offre une solution pour des besoins simples de persistance en utilisant des fichiers plats. Il propose une solution standard ind´ependante de l’impl´ementation. Un fichier DBM s’utilise comme un dictionnaire, donc relativement simplement, seul l’initialisation est diff´erente (ouverture du fichier). Les donn´ees sont manipul´ees comme des chaˆınes et accessibles `a l’aide de cl´es. open(name, ’c’) ouvre le fichier nomm´e name (’c’ signifie en le cr´ eant s’il n’exsite ( (
pas ). ) )
> > > i m po r t a n yd b m > >> f il e = a ny db m . o pe n ( ’ bl ab la ’ , ’ c ’)
ementations, pour ˆetre sˆ ur que les close() ferme le fichier (requis ou non selon les impl´ donn´ees sont sauv´ees il vaut mieux utiliser explicitement close). > > > f i le . c l o se ( )
La lecture et l’´ecriture se fait comme dans un dictionnaire, mais les cl´es sont obligatoirement des chaˆınes. L’exemple suivant cr´ee deux entr´ees (foo et bar) dans le fichier DBM, les re-lit et ferme le fichier. > >> f il e = a ny db m . o pe n ( ’ bl ab la ’ , ’ c ’) > >> f il e [ ’ fo o ’] = ’ p er ri er c f oo ’ > >> f il e [’ ba r ’] = ’ cd b ar ; m or e b ee r ’ > > > p r in t f i le [ ’ f o o ’ ] p er ri er c f oo > > > p r in t f i le [ ’ b a r ’ ] cd bar ; mo re bee r > > > f i le . c l o se ( )
71
72
Python et la persistance de donn´ ees
has key() test la pr´esence d’une cl´e. > >> f il e = a ny db m . o pe n ( ’ bl ab la ’ , ’ c ’) > > > f i le . h a s _ ke y ( ’ f o o ’ ) 1
keys() donne la liste des cl´es du fichier. Obtenir les cl´e est un pr´e-requis a` tout parcours
d’un fichier DBM. > > > f i le . k e y s ( ) [ ’ f oo ’ , ’ b ar ’ ] > >> f or k ey i n f il e . k ey s ( ): p ri nt k ey , f il e [ ke y ] f oo ’ p er ri er c f oo ’ bar ’ cd bar ; mor e b eer ’
ees d’un fichier. footnote len() donne le nombre d’entr´ > > > l en ( f i l e ) 2
del permet de supprimer une entr´ee (ce qui suit le fonctionnement standard d’un diction-
naire). > > > f i le . k e y s ( ) [ ’ f oo ’ , ’ b ar ’ ] > >> d el f il e [ ’ fo o ’ ] > > > f i le . k e y s ( ) [’bar’] > > > l en ( f i l e ) 1 > > > f i le . c l o se ( )
5.1.2
Limitations
Les fichiers DBM permettent uniquement de rendre persistant des chaˆınes de caract`eres. La conversion objet vers chaˆıne (et r´eciproquement) doit ˆetre g´er´ee manuellement, ce qui rend leur utilisation rapidement complexe pour des objets composites.
5.2 5.2.1
Pickle et Shelve Object pickling
Le module pickle (standard en Python) permet la s´erialisation des objets m´emoire en chaˆınes (et r´eciproquement). Il est utile pour la persistance et le transferts de donn´ees sur un r´eseau. > > > i m po r t p i ck l e
c 2003-2007, Rapha¨el Marvie
5.2 Pickle et Shelve
73
La manipulation des donn´ees utilise un fichier par action de s´erialisation, o` u les donn´ees sont stock´ees sous forme de chaˆınes. Il n’y a pas de structuration des donn´ees (donc pas de recherche rapide).
5.2.2
(D´ e)S´erialisation et fichiers
La classe Pickler est un s´erialiseur vers un fichier et la fonction dump() r´ealise la s´erialisation d’un objet (il existe aussi une fonction ´equivalente dans le module). L’exemple suivant s´erialise un dictionnaire dans le fichier foo.saved. > >> > >> > >> >>> >>>
f oo = { ’a ’: ’ aa a ’, ’ b’ : ’ bb b ’, ’ c’ : ’ cc c ’} o ut pu t = o pe n ( ’ fo o . sa ve d ’ , ’ w ’) p = p ic kl e . P ic kl er ( o u tp ut ) #(1) p . d u mp ( f o o ) #(2) o u tp u t . c l os e ( )
ou bien > >> o ut pu t = o pe n ( ’ fo o . sa ve d ’ , ’ w ’) > > > p i ck l e . d um p ( f oo , o u tp u t ) > > > o u tp u t . c l os e ( )
#(1,2)
La classe Unpickler est un d´e-s´erialiseur depuis un fichier et la fonction load() r´ealise la d´e-s´erialisation d’un objet (il existe aussi une fonction ´equivalente dans le module). L’exemple suivant recharge depuis le fichier foo.saved le dictionnaire s´erialis´e dans l’exemple pr´ec´edent. > >> i np ut = o pe n ( ’ fo o . sa ve d ’ , ’ r ’) > > > p = p i ck l e . U n p ic k l er ( i n p u t ) > >> f oo 2 = p . l oa d () > > > i n pu t . c l o se ( ) > > > f oo 2 { ’ a ’: ’ a aa ’ , ’ b ’: ’ b bb ’ , ’ c ’: ’ c cc ’ }
#(1) #(2)
ou bien > >> i np ut = o pe n ( ’ fo o . sa ve d ’ , ’ r ’) > > > f oo 2 = p i ck l e . l oa d ( i n pu t ) > > > i n pu t . c l o se ( )
5.2.3
#(1,2)
(D´e)S´ erialisation et chaˆınes
erialise un objet vers une chaˆıne (et non plus vers un fichier). Cette op´eration dumps() s´ est pratique pour ´echanger des messages sur un r´eseau par exemple. > >> d at a = p ic kl e . d um ps ( f oo ) > > > d a ta " ( d p 0 \ n S ’ a ’ \ n p 1 \ n S ’ a a a ’ \ n p2 \ n s S ’ c ’ \ n p3 \ n S ’ c c c ’ \ n p4 \ \nsS’b’\np5\nS’bbb’\np6\ns."
c 2003-2007, Rapha¨el Marvie
74
Python et la persistance de donn´ ees
loads() d´e-s´erialise une chaˆıne vers un objet. > >> f oo 3 = p ic kl e . l oa ds ( d a ta ) > > > f o o3 { ’ a ’: ’ aa a ’ , ’ c ’: ’ c cc ’ , ’ b ’: ’ b bb ’ }
5.2.4
DBM + Pickle = Shelves
Le module shelves exploite les deux modules pr´ec´edents (en offrant l’interface du second) : – pickle pour s´erialiser les objets (´eventuellement complexes), – anydbm pour la gestion des cl´es et des fichiers. L’exemple suivant cr´ee un fichier base dans lequel nous stockons un dictionnaire associ´e `a la cl´e foo. Puis, nous r´eouvrons ce fichier pour r´ecup´erer, dans ce dictionnaire, l’entr´ee associ´ee a` la cl´e a. > > > i m po r t s h el v e > > > b as e = s h el v e . o pe n ( ’ b a se ’ ) > >> b as e [ ’ fo o ’] = { ’ a ’: [ ’ a1 ’ , ’ a2 ’ ] , ’ b ’: [ ’ b1 ’ , ’ b2 ’ ]} > > > b as e . c l o se ( ) > > > b a se 2 = s h el v e . o pe n ( ’ b a se ’ ) > > > p r in t b a se 2 [ ’ f oo ’ ] [ ’ a ’ ] [’a1’,’a2’] > > > b a se 2 . c l o se ( )
5.2.5
Remarques
– La concurrence de mise a` jour n’est pas support´ee avec shelve, une possibilit´e est d’utiliser fcntl. – La d´efinition des classes doit ˆetre importable au moment du chargement des donn´ees par pickle. – La compatibilit´e des fichiers n’est pas garantie entre deux impl´ementations de DBM. Il n’y a donc que portabilit´e du code, pas des donn´ees.
5.3 5.3.1
Python et SQL Exemple avec Postgres
Python inclut un module d’acc`es aux bases de donn´ees offrant une interface standardis´ee (de facto). Des mises en oeuvre existent pour les diff´erentes bases de donn´ees courantes. Toutefois, l’utilisation de chaque base peut varier, donc le code Python d’acc`es a` une base n’est pas 100% portable 1 . 1
Il est donc recommand´ e dans une application de d´efinir une couche d’abstraction de la base.
c 2003-2007, Rapha¨el Marvie
5.3 Python et SQL
75
L’utilisation d’une base de donn´ees est ici illustr´e avec une base Postgres2 . Le module psycopg fournit l’acc`es a` une base Postgres depuis Python. Il permet de trouver le bon compromis entre la puissance du langage et de la base de donn´ees : r´ealiser une partie des traitements sur les donn´ees en SQL et une partie en Python.
Cr´ eation d’une base personnelle sur la machine locale. – cr´eation de la base sur le filesystem (une fois), – lancement du serveur (` a chaque d´emarrage de la machine), – cr´eation de la base (et d’utilisateurs si n´ecessaire), – administrateur = user au sens Unix, sans mot de passe. $ i n it d b - D < r e pe r to i re > $ p g_ ct l - D < r ep er to ir e > s ta rt [ - o " - i" # pour le r´ es eau] $ c r ea te db t es t
5.3.2
Op´ erations de base
L’op´eration connect() retourne un objet repr´esentant la connexion a` une base de donn´ees. Les arguments sont variables selon les bases ou les contextes (par exemple, host n’est pas obligatoire si la base est locale). > > > i m po r t p s yc o pg > > > c o n ne x i on = p s yc o pg . c o n n e ct ( . .. " h o st = l o c a l ho s t d b na m e = t e st u se r = r a fi " )
Des curseurs sont utilis´es pour les interactions avec la base : ´emission de requˆetes SQL. Ils sont cr´e´es par l’objet connexion. Un curseur offre la m´ethode execute qui permet de demander a` la base l’´evaluation d’une requˆete SQL. Le curseur est ici utilis´e pour cr´eer une table test1 ayant un seul champ val de type entier. Ensuite, le curseur est utilis´e pour faire 10 insertions dans cette table. > > > c u rs e ur = c o nn e x io n . c u r s or ( ) > > > c u rs e ur . e x e c u te ( ... " CREATE TABLE test1 ( val int4 )" ) > >> f or i in r an ge ( 1 0) : ... curseur . execute ( ... " INSERT INTO test1 VALUES (% d ) " , (i ,))
Exemples d’insertions. Une insertion peut se faire en utilisant un tuple (comme dans l’exemple pr´ec´edent) ou un dictionnaire pour fournir les valeurs. Dans le cas de l’utilisation des tuples, les donn´ ees sont prises dans l’ordre du tuple qui doit ˆetre de mˆeme longueur que le tuple de format de la requˆete (argument de la clause VALUES). L’exemple suivant cr´ ee une nouvelle table et utilise un dictionnaire pour fournir les 2
La mˆeme chose avec MySQL diff`ere peu, par exemple sur la connexion et la gestion des commits, `a ajouter.
c 2003-2007, Rapha¨el Marvie
76
Python et la persistance de donn´ ees valeurs a` ins´erer. La m´ethode executemany permet d’ins´erer une s´equence de donn´ees dans une table sans avoir `a faire une boucle en Python. >>> >>> ... >>> ... ... > >> >>> ...
c u rs e ur = c o nn e x io n . c u r s or ( ) c u rs e ur . e x e c u te ( ’ ’ ’ C R E AT E T A BL E t e st 2 ( n a me t ex t , fir stna me text )’ ’ ’) c u rs e ur . e x e c u te ( ’ ’ ’ I N S ER T I NT O t e st 2 V AL UE S (%( n ame )s , %( f ir st na me ) s) ’’ ’, { ’ name ’ : ’ doe ’ , ’ fi rs tn am e ’: ’ joh n ’}) v al eu rs = ( ( ’ ma rt in ’ , ’ p ie rr e ’ ), ( ’ d up on t ’ , ’ p au l ’ )) c u rs e ur . e x e c u t em a n y ( ’ ’ ’ I NS E RT I N TO t e st 2 VALUES (% s , % s ) ’’ ’ , valeurs )
Les resultats de requˆetes (r´eponses a` une command select) sont des structures de donn´ees Python : listes (ensemble des r´eponses) de tuples (les donn´ees d’une r´eponse). Les op´eration fetchone() et fetchall() offertes par le curseur permettent de r´ecup´erer respectivement une valeur (en fait les valeurs une par une) ou toutes les valeurs3 . L’exemple suivant ex´ecute une requˆete sur la base et r´ecup`ere d’abord la premi`ere r´eponse, en affichant le premier champs, puis toutes les r´eponses restantes, en affichant les deux champs. > > > c u rs e ur . e x e c u te ( " S E L E CT * F RO M t e st 2 " ) > > > p r e m = c u rs e ur . f e t c h on e ( ) > > > p r in t p r em [ 0 ] doe > > > v a le u rs = c u rs e u r . f e tc h al l ( ) > >> f or v in v al eu rs : ... print v [0] , v [1] ... m a r t in p i e r r e d u po n t p a ul
close() demande explicitement la fermeture d’une connexion (c’est implicite lorsque
l’objet connexion est d´etruit au sens Python). commit() valide une transaction avec la base (offert par un objet connexion). rollback() annule une transaction avec la base (offert par un objet connexion). autocommit(1|0) active ou d´ esactive l’autocommit des op´ erations (offert par l’objet
connexion).
5.3.3
Gestion de dates
Le module mx (associ´e `a psycopg) fournit des classes, principalement DateTime, pour la gestion des dates et timestamps. 3
Attention sur les select retournant beaucoup de r´eponses, le fetchall() a une borne sup´erieure.
c 2003-2007, Rapha¨el Marvie
5.4 Exercices
77
> >> i mp or t m x > > > m x . D a te T i me . n o w ( ) < D at e Ti me o bj ec t f or ’ 2 00 3 - 06 - 1 2 1 8 :4 7 :3 6 .5 4 ’ a t 8 a a0 a3 0 > > > > t 1 = p s yc o pg . T i m e s t a mp F r om M x ( m x . D a t eT i me . n o w ( ) ) > >> t 2 = p sy co pg . T i m es ta m p ( 20 03 , 0 6 , 15 , 1 5 , 32 , 0 7)
5.3.4
Gestion de donn´ ees binaires
L’utilisation de donn´ees binaires (images ou sons par exemple) doit ˆetre d´eclar´e explicitement a` l’insertion avec la classe Binary. L’exemple suivant cr´ee une table pour stocker des photos avec leur nom, puis ins`ere une photo. >>> >>> ... ... >>> . .. . ..
c u rs e ur = c o nn e x io n . c u r s or ( ) c u rs e ur . e x e c u te ( ’ ’ ’ C R E AT E T A BL E t e st 3 ( i d i nt 4 , name text , photo bytea )’ ’’) c u rs e ur . e x e c u te ( ’ ’ ’ I N S ER T I NT O t e st 3 V AL UE S ( %d , % s , % s ) ’’ ’ , ( 1 , ’ s h oe s . j p g ’ , p s yc o pg . B i n a ry ( o p e n ( ’ s ho e s . j pg ’ ) . r e ad ( ) ) ) )
La r´ecup´eration des donn´ees binaire est similaire aux donn´ees classiques. L’exemple suivant r´ecup`ere la photo qui est stock´ee dans la base et la sauvegarde dans un fichier nomm´e new_shoes.jpg. >>> >>> > >> >>>
5.4 5.4.1
c u rs e ur = c o nn e x io n . c u r s or ( ) c u rs e ur . e x e c u te ( ’ S E L E CT * F RO M t e st 3 ’ ) v al = c ur se ur . f e tc h on e ( ) o p en ( ’ n e w_ ’ + v al [ 1 ] , ’ w b ’ ). w r i te ( v a l [ 2 ])
Exercices Module Mod` ele du MVC ( (
) )
Ecrire un script Python qui cr´ee une table repr´esentant des ´etudiants avec les champs suivants (le type des donn´ees est pr´ecis´e entre parenth`eses) : num dossier (int4), nom (text), pr´enom (text), universit´e (text), discipline (text), niveau (int4), moyenne(int4). Ecrire un programme Python chargeant l’ensemble des donn´ees du fichier etudiants.xml dans cette table. Pour cela, une partie du code de l’exercice pr´ec´edent est r´eutilisable pour le parcours de l’arbre DOM.
5.4.2
Module Contrˆ oleur du MVC ( (
) )
D´evelopper trois classes offrant une m´ethode eval() r´ealisant les traitements suivants sur la base de donn´ees : c 2003-2007, Rapha¨el Marvie
78
Python et la persistance de donn´ ees
– obtenir la liste des num´eros de dossiers, nom et pr´enom des ´etudiants, – obtenir la fiche compl`ete d’un ´etudiant par rapport `a son num´ero de dossier, – ins´erer une fiche d’´etudiant en fournissant toutes les informations. D´evelopper une classe Controleur qui est une composition des trois classes pr´ec´edentes et qui fournit des m´ethodes pour acc´eder aux instances lors de l’ex´ecution (pour permettre les interactions comme d´ecrite dans l’exemple suivant). c t rl = C o n tr o l eu r ( . . .) l i s t_ a l l_ c t rl = c t rl . g e t _ l i s t_ a l l_ c t r l ( ) s t u de n t _l i s t = l i s t_ a l l_ c t rl . e v a l ( )
c 2003-2007, Rapha¨el Marvie
Chapitre 6 Python et les interfaces graphiques 6.1
Python et Tkinter
6.1.1
Tkinter
Le module Tkinter [3] est bas´e sur Tk, la librairie d´evelopp´ee par J. Ousterout pour faire des interfaces graphiques en Tcl[10], et disponible sur plusieurs plates-formes (dont X11, MS-Windows, Mac OS X). Tkinter est le standard de facto pour Python offrant une vision objet de Tk. Toutefois, Tcl est un langage o` u tout est chaˆınes de caract`eres. Il en r´esulte qu’un certain nombre de valeur utilis´ees dans le cas de Tkinter sont des chaˆınes de caract`eres (utilis´ees directement comme tel ou bien sous couvert de variables offertes par le module). Comme tout programme avec une interface graphique, l’ex´ecution est dirig´ee par les ´ev´enements. Les interactions entre Python et l’interface graphique peut prendre plusieurs formes : – Traitement GUI Python → Tkinter → Tk → Librairie graphique. – Ev`enement graphique → Tk → Tkinter → Traitements Python.
6.1.2
Premier pas
Le hello world ! version graphique tient en quatre lignes, pr´esent´ees dans l’exemple suivant. Le module Tkinter est charg´e. Un widget (ici un Label) est cr´e´e puis ajout´e a` l’environnement graphique (pack). Enfin, la boucle d’´ev´enements est d´emarr´ee. Elle est active tant que la fenˆetre n’est pas ferm´ee (et le prompt de l’interpr´eteur reste suspendu). ( (
>>> >>> >>> >>>
) )
i m po r t T k in t er w i dg e t = T k in t e r . L ab e l ( No ne , t e xt = ’ h e l lo w o rl d ! ’ ) w i dg e t . p ac k ( ) w i dg e t . m a i nl o op ( )
79
80
Python et les interfaces graphiques
6.1.3
Configuration de widgets
Dans le cas du Label de hello world ! , il n’y a pas de widget parent (premier argument e directement a` la fenˆetre par d´efaut. Le texte du Label repr´esente sa None). Il est attach´ configuration. La configuration peut ˆetre r´ealis´ee ou chang´ee apr`es la cr´eation avec la m´ethode config() des widgets. L’exemple suivant est identique en terme de r´esultat a` l’exemple pr´ec´edent. ( (
>>> >>> >>> >>>
6.1.4
) )
w i dg e t = T k in t e r . L ab e l ( N on e ) w i dg e t . c o nf i g ( t ex t = ’ h e ll o w o rl d ! ’ ) w i dg e t . p ac k ( ) w i dg e t . m a i nl o op ( )
Composition de widgets avec pack
Les composition des widgets est d´el´egu´e au gestionnaire de g´eom´etrie. – Le placement du widget se fait par rapport a` son contenant (avec l’option de configuration side) en utilisant un placement cardinal (Tkinter.TOP, Tkinter.LEFT, efaut, un widget est attach´e en haut, ou Tkinter.RIGHT, Tkinter.BOTTOM). Par d´ au-dessous des widgets existants – Si l’on souhaite une occupation maximale de l’espace, utiliser l’option de configuration expand=YES. La direction de l’occupation maximale est pr´ecis´ee par fill. Elle peut ˆetre en largeur (Tkinter.X), en hauteur (Tkinter.Y) ou les deux (Tkinter.BOTH).
6.1.5
Lancer des commandes
Pour initier un traitement depuis une interface graphique, la m´ethode courante est de d´efinir un bouton, un menu, une scrollbar, etc. et d’y associer un traitement (fonction ou m´ethode sans argument). L’exemple suivant cr´ee un bouton et y associe la commande sys.exit pour quitter l’ex´ ecution du programme (dans le cas courant l’interpr´eteur complet). L’option text pr´ecise le texte qui apparaˆıt sur le bouton. > >> >>> >>> >>> >>>
i mp or t s ys w i dg e t = T k in t e r . B u tt o n ( N on e ) w i dg e t . c o nf i g ( t ex t = ’ p r es s t o q u it ’ , c o mm a n d = s ys . e x i t ) w i dg e t . p ac k ( ) w i dg e t . m a i nl o op ( )
c 2003-2007, Rapha¨el Marvie
6.1 Python et Tkinter
6.1.6
81
Composition et redimensionnement
Relations entre la composition et le redimensionnement : – par d´efaut le widget conserve sa taille initiale, – pour suivre les changements utiliser expand. L’exemple suivant configure le bouton de telle sorte qu’il occupe toujours tout l’espace en largeur lors du redimensionnement de la fenˆ etre. Par contre, le bouton n’occupe pas tout l’espace en hauteur. >>> > >> >>> >>> >>> >>>
i m po r t T k in t er i mp or t s ys w i dg e t = T k in t e r . B u tt o n ( N on e ) w i dg e t . c o nf i g ( t ex t = ’ p r es s t o q u it ’ , c o mm a n d = s ys . e x i t ) w i dg e t . p ac k ( e x p an d = T k i n te r . Y ES , f i ll = T k i n t er . X ) w i dg e t . m a i nl o op ( )
6.1.7
Boutons et traitements
Un bouton ne peut d´eclencher qu’un traitement, il est donc souvent n´ecessaire d’utiliser une fonction qui regroupe les traitements. Dans l’exemple suivant, la fonction handler affiche hello world sur la sortie standard avant de quitter l’application. ( (
>>> > >> >>> ... ... ... >>> >>> >>> >>>
) )
i m po r t T k in t er i mp or t s ys d ef h a nd l er ( ) : print ’ hello world !’ sys . exit () w i dg e t = T k in t e r . B u tt o n ( N on e ) w i dg e t . c o nf i g ( t ex t = ’ p r es s t o q u it ’ , c o mm a n d = h a nd l e r ) w i dg e t . p ac k ( e x p an d = T k i n te r . Y ES , f i ll = T k i n t er . X ) w i dg e t . m a i nl o op ( )
Une classe d’utilisation d’un widget graphique est une bonne mani`ere de cr´eer une relation forte entre widget, traitements et donn´ees. Cet ensemble (bouton, donn´ees, traitec 2003-2007, Rapha¨el Marvie
82
Python et les interfaces graphiques
ments) est facilement r´eutilisable. L’exemple pr´esente un exemple de bouton pour quitter une application o` u le message est param´etrable. >>> > >> >>> ... ... ... ... ... ... ... ... ... > >> >>>
i m po r t T k in t er i mp or t s ys c l as s H e l lo Q u it B u tt o n : def __ init__ ( self , msg =’ Quit ’): self . msg = msg b = Tkinter . Button ( None ) b .config ( text = self .msg , command = self . handle ) b . pack () def handle (self ): print self . msg sys . exit () h qb = H e ll o Qu i tB u tt o n () T k in t e r . m a in l oo p ( )
Un handler peut ˆetre d´efini comme un objet : d´efinition d’une classe repr´esentant une fonction et instanciation pour l’utilisation. L’exemple suivant red´efinit le handler pr´ec´edent comme une classe. >>> > >> >>> ... ... ... ... ... ... ... >>> >>> >>> >>>
6.1.8
i m po r t T k in t er i mp or t s ys c l as s C a l la b le : def __ init__ ( self ): self . msg = ’ hello world ! ’ def __ call__ ( self ): print self . msg import sys sys . exit () w i dg e t = T k in t e r . B u tt o n ( N on e ) w i dg e t . c o nf i g ( t ex t = ’ h e ll o ’ , c o mm a nd = C a l l a bl e ( ) ) w i dg e t . p ac k ( ) T k in t e r . m a in l oo p ( )
D´ efinition de bindings
La fonction bind permet d’associer une fonction (` a 1 argument) a` un ´ev´enement et `a un widget. Les ´ev´enements les plus courants sont les clics souris et la saisie au clavier. L’exemple suivant cr´ee deux fonctions pour afficher hello world ! et pour afficher bye sur la sortie standard avant de quitter le programme. Ensuite, il cr´ee un label et y associe la fonction hello au clic gauche et la fonction quit au double clic. ( (
) )
( (
) )
> > > i m po r t T k in t er > >> i mp or t s ys
c 2003-2007, Rapha¨el Marvie
6.1 Python et Tkinter
83
> > > d ef h e ll o ( e v e nt ) : ... print ’ hello world !’ ... > > > d ef q u it ( e v e n t ): ... print ’ bye ’ ... sys . exit () ... > > > w i dg e t = T k in t e r . L ab e l ( No ne , t e xt = ’ p r e ss ’ ) > > > w i dg e t . p ac k ( ) > > > w i d g e t . b i n d ( ’ < B u t to n - 1 > ’ , h e l l o ) ’805810704hello’ > > > w i d g e t . b i n d ( ’ < D o u bl e - 1 > ’ , q u i t ) ’805810224quit’ > > > w i dg e t . m a i nl o op ( )
L’´ev´enement re¸cu par un handler contient des informations qui peuvent ˆetre interpr´et´ees dans le cadre du traitement. L’exemple suivant d´efinit deux fonctions dont le but est d’afficher un caract`ere tap´e au clavier et d’afficher les coordonn´ees de la souris. La classe Tk repr´esente la fenˆetre principale du programme. Le label cr´e´e est associ´e a` cette fenˆetre (premier param`etre du constructeur). Puis, les deux fonctions sont associ´ees au clavier et au clic sur le label. L’utilisation de focus s´electionne le label pour recevoir les ´ev´enements clavier. Enfin, la boucle d’´ev´enements est d´emarr´e sur la fenˆetre principale. Lorsque la fenˆetre est active et que l’on tape une touche au clavier, cela g´en`ere un ´ev´enement pass´e a` la fonction onKey qui va en extraire le caract`ere associ´e. (Mˆeme principe pour le clic de souris.) ( (
) )
> > > i m po r t T k in t er > > > d ef o n Ke y ( e v e nt ) : ... print ’ got key ’, event . char ... > > > d ef o n Cl i ck ( e v e n t ) : ... p rin t e ve nt . widget , ev ent .x , ev ent . y ... > >> r oo t = T ki nt er . T k () > > > l a b = T k in t er . L a b e l ( ro ot , t ex t = ’ h e ll o w o rl d ’ ) > > > l a b . b i n d ( ’ < K e y P re s s > ’ , o n K ey ) ’805787968onKey’ > > > l a b . b i n d ( ’ < B u t to n - 1 > ’ , o n C l i ck ) ’808388888onClick’ > > > l ab . f o c us ( ) > > > l ab . p a c k ( ) > > > r oo t . m a i n lo o p ( ) . 8 05 7 89 3 68 3 0 1 4 . 8 05 7 89 3 68 4 4 1 1 got key e got key r