IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)

Plongez au coeur de Python ,De débutant à expert


précédentsommairesuivant

III. Types prédéfinis

Avant de revenir à votre premier programme Python, une petite digression est de rigueur car vous devez absolument connaître les dictionnaires, les tuples et les listes (tout ça !).
Si vous être un programmeur Perl, vous pouvez probablement passer rapidemment sur les points concernant les dictionnaires et les listes mais vous devrez quand même faire attention aux tuples.

III-A. Présentation des dictionnaires

Un des types de données fondamentaux de Python est le dictionnaire, qui défini une relation 1 à 1 entre des clés et des valeurs.

En Python, un dictionnaire est comme une table de hachage en Perl. En Perl, les variables qui stockent des tables de hachage débutent toujours par le caractère %.
En Python vous pouvez nommer votre variable comme bon vous semble et Python se chargera de la gestion du typage.

Un dictionnaire Python est similaire à une instance de la classe Hashtable en Java.

Un dictionnaire Python est similaire à une instance de l'objet Scripting.Dictionnary en Visual Basic.

III-A-1. Définition des dictionnaires

Exemple 3.1. Définition d'un dictionnaire
 
Sélectionnez
	>>> d = {"server":"mpilgrim", "database":"master"} ***1***
	>>> d
	{'server': 'mpilgrim', 'database': 'master'}
	>>> d["server"]                                    ***2***
	'mpilgrim'
	>>> d["database"]                                  ***3***
	'master'
	>>> d["mpilgrim"]                                  ***4***
	Traceback (innermost last):
	  File "<interactive input>", line 1, in ?
	KeyError: mpilgrim

***1*** D'abord, nous créons un nouveau dictionnaire avec deux éléments que nous assignons à la variable d. Chaque élément est une paire clé-valeur et l'ensemble complet des éléments est entouré d'accolades.
***2*** 'server' est une clé et sa valeur associée, référencée par d["server"], est 'mpilgrim'.
***3*** 'database' est une clé et sa valeur associée, référencée par d["database"], est 'master'.
***4*** Vous pouvez obtenir les valeurs par clé, mais pas les clés à partir de leur valeur. Donc d["server"] est 'mpilgrim', mais d["mpilgrim"] déclenche une exception car 'mpilgrim' n'est pas une clé.

III-A-2. Modification des dictionnaires

Exemple 3.2. Modification d'un dictionnaire
 
Sélectionnez
>>> d
{'server': 'mpilgrim', 'database': 'master'}
>>> d["database"] = "pubs" 1
>>> d
{'server': 'mpilgrim', 'database': 'pubs'}
>>> d["uid"] = "sa"        2
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'pubs'}

***1*** Vous ne pouvez avoir de clés dupliquées dans un dictionnaire. L'assignation d'une valeur à une clé existante a pour effet d'effacer l'ancienne valeur.
***2*** Vous pouvez ajouter de nouvelles paires clé-valeur à tout moment. La syntaxe est identique à celle utilisée pour modifier les valeurs existantes. (Oui, cela vous posera problème si vous essayez d'ajouter de nouvelles valeurs alors que vous ne faites que modifier constamment la même valeur parce que votre clé n'a pas changé de la manière que vous espériez)

Notez que le nouvel élément (clé 'uid', valeur 'sa') à l'air d'être au milieu. En fait c'est par coïncidence que les éléments avaient l'air d'être dans l'ordre dans le premier exemple, c'est tout autant une coïncidence qu'ils aient l'air dans le désordre maintenant.

Les dictionnaires ne sont liés à aucun concept d'ordonnancement des éléments. Il est incorrect de dire que les élément sont «dans le désordre», il ne sont tout simplement pas ordonnés. C'est une distinction importante qui vous ennuiera lorsque vous souhaiterez accéder aux éléments d'un dictionnaire d'une façon spécifique et reproductible (par exemple par ordre alphabétique des clés). C'est possible, mais cette fonctionalite n'est pas integrée au dictionnaire.

Quand vous utilisez des dictionnaires, vous devez garder à l'esprit le fait que les clés sont sensibles à la casse.

Exemple 3.3. Les clés des dictionnaires sont sensibles à la casse
 
Sélectionnez
>>> d = {}
>>> d["key"] = "value"
>>> d["key"] = "other value" ***1***
>>> d
{'key': 'other value'}
>>> d["Key"] = "third value" ***2***
>>> d
{'Key': 'third value', 'key': 'other value'}

***1*** Assigner une valeur a une clé existante remplace l'ancienne valeur par la nouvelle. ***2*** Ici la valeur n'est pas assignée à une clé existante parce que les chaînes en Python sont sensibles à la casse, donc 'key' n'est pas la même chose que 'Key'. Une nouvelle paire clé/valeur est donc créée dans le dictionnaire, elle peut vous sembler similaire à la précédente, mais pour Python elle est complètement différente.

Exemple 3.4. Mélange de types de données dans un dictionnaire
 
Sélectionnez
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'pubs'}
>>> d["retrycount"] = 3 1
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3}
>>> d[42] = "douglas"   2
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master',
42: 'douglas', 'retrycount': 3}

***1*** Les dictionnaires ne servent pas uniquement aux chaînes de caractères. Les valeurs d'un dictionnaire peuvent être de n'importe quel type de données, y compris des chaînes, des entiers, des objets et même d'autres dictionnaires. Au sein d'un même dictionnaire les valeurs ne sont pas forcémment d'un même type, vous pouvez les mélanger à votre guise.
***2*** Les clés d'un dictionnaire sont plus restrictives, mais elles peuvent être des chaînes, des entiers et de quelques autres types encore (nous verrons cela en détail plus tard). Vous pouvez également mélanger divers types de données au sein des clés d'un dictionnaire.

III-A-3. Enlever des éléments d'un dictionnaire

Exemple 3.5. Enlever des éléments d'un dictionnaire
 
Sélectionnez
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master',
42: 'douglas', 'retrycount': 3}
>>> del d[42] ***1***
>>> d
{'server': 'mpilgrim', 'uid': 'sa', 'database': 'master', 'retrycount': 3}
>>> d.clear() ***2***
>>> d
{}

***1*** L'instruction del vous permet d'effacer des éléments d'un dictionnaire en fonction de leur clé.
***2*** La méthode clear efface tous les éléments d'un dictionnaire. Notez que l'ensemble fait d'accolades vides signifie un dictionnaire sans éléments.

Pour en savoir plus sur les dictionnaires

III-B. Présentation des listes

Les listes sont le type de données à tout faire de Python. Si votre seule expérience des listes sont les tableaux de Visual Basic ou (à Dieu ne plaise) les datastores de Powerbuilder, accrochez-vous pour les listes Python.

Une liste en Python est comme un tableau Perl. En Perl, les variables qui stockent des tableaux débutent toujours par le caractère @, en Python vous pouvez nommer votre variable comme bon vous semble et Python se chargera de la gestion du typage.

Une liste Python est bien plus qu'un tableau en Java (même s'il peut être utilisé comme tel si vous n'attendez vraiment rien de mieux de la vie). Une meilleure analogie serait la classe ArrayList, qui peut contenir n'importe quels objets et qui croît dynamiquement au fur et à mesure que de nouveaux éléments y sont ajoutés.

III-B-A. Definition d'une liste

Exemple 3.6. Definition d'une liste
 
Sélectionnez
>>> li = ["a", "b", "mpilgrim", "z", "example"] ***1***
>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[0]                                       ****2***
'a'
>>> li[4]                                       ***3***
'example'

***1*** Premièrement, nous définissons une liste de 5 éléments. Notez qu'ils conservent leur ordre d'origine. Ce n'est pas un accident. Une liste est un ensemble ordonné d'éléments entouré par des crochets.
***2*** Une liste peut être utilisée comme un tableau dont l'indice de base est zéro. Le premier élément de toute liste non vide est toujours li[0].
***3*** Le dernier élément de cette liste de 5 éléments est li[4] car les listes sont toujours indicées à partir de zéro.

Exemple 3.7. Indices de liste négatifs
 
Sélectionnez
>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[-1] 1
'example'
>>> li[-3] 2
'mpilgrim'

***1*** Un indice négatif permet d'accéder aux éléments à partir de la fin de la liste en comptant à rebours. Le dernier élément de toute liste non vide est toujours li[-1].
***2*** Si vous trouvez que les indices négatifs prêtent à confusion, voyez-les comme suit : li[n] == li[n - len(li)]. Donc dans cette liste, li[-3] == li[5 - 3] == li[2].

Exemple 3.8. Découpage d'une liste
 
Sélectionnez
>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[1:3]  ***1***
['b', 'mpilgrim']
>>> li[1:-1] ***2***
['b', 'mpilgrim', 'z']
>>> li[0:3]  ***3***
['a', 'b', 'mpilgrim']

***1*** Vous pouvez obtenir un sous-ensemble d'une liste, appelé une «tranche» (slice), en spécifiant deux indices. La valeur de retour est une nouvelle liste contenant les éléments de la liste, dans l'ordre, en démarrant du premier indice de la tranche (dans ce cas li[1]), jusqu'à au second indice de la tranche non inclu (ici li[3]).
***2*** Le découpage fonctionne si un ou les deux indices sont négatifs. Pour vous aider, vous pouvez les voir commer ceci : en lisant la liste de gauche à droite, le premier indice spécifie le premier élément que vous désirez et le second indice spécifie le premier élément dont vous ne voulez pas. La valeur de retour est tout ce qui se trouve entre les deux.
***3*** Les listes sont indicées à partir de zéro, donc li[0:3] retourne les trois premiers éléments de la liste, en démarrant à li[0] jusqu'à li[3] non inclu.

Exemple 3.9. Raccourci pour le découpage
 
Sélectionnez
>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li[:3] ***1***
['a', 'b', 'mpilgrim']
>>> li[3:] ***2*** ***3***
['z', 'example']
>>> li[:]  ***4***
['a', 'b', 'mpilgrim', 'z', 'example']

***1*** Si l'indice de tranche de gauche est 0, vous pouvez l'omettre et 0 sera implicite. Donc li[:3] est la même chose que li[0:3] dans le premier exemple.
***2*** De la même manière, si l'indice de tranche de droite est la longueur de la liste, vous pouvez l'omettre. Donc li[3:] est pareil que li[3:5], puisque la liste a 5 éléments.
***3*** Remarquez la symétrie. Dans cette liste de 5 éléments, li[:3] retourne les 3 premiers éléments et li[3:] retourne les deux derniers. En fait li[:n] retournera toujours les n premiers éléments et li[n:] le reste, quelle que soit la longueur de la liste.
***4*** Si les deux indices sont omis, tous les éléments de la liste sont inclus dans la tranche. Mais ce n'est pas la même chose que la liste li; c'est une nouvelle liste qui contient les même éléments. li[:] est un raccourci permettant d'effectuer une copie complète de la liste.

III-B-B. Ajout d'éléments à une liste

Exemple 3.10. Ajout d'éléments à une liste
 
Sélectionnez
>>> li
['a', 'b', 'mpilgrim', 'z', 'example']
>>> li.append("new")               ***1***
>>> li
['a', 'b', 'mpilgrim', 'z', 'example', 'new']
>>> li.insert(2, "new")            ***2***
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new']
>>> li.extend(["two", "elements"]) ***3***
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']

***1*** append ajoute un élément à la fin de la liste. ***2*** insert insère un élément dans la liste. L'argument numérique est l'indice du premier élément qui sera décalé. Notez que les éléments de la liste ne sont pas obligatoirement uniques ; il y a maintenant 2 éléments distincts avec la valeur 'new', li[2] et li[6]. ***3*** extend concatène des listes. Notez que vous n'appelez pas extend avec plusieurs arguments mais bien avec un seul argument qui est une liste. Dans le cas présent, la liste est composée de deux éléments.

Exemple 3.11. Différence entre extend et append
 
Sélectionnez
>>> li = ['a', 'b', 'c']
>>> li.extend(['d', 'e', 'f']) ***1***
>>> li
['a', 'b', 'c', 'd', 'e', 'f']
>>> len(li)                    ***2***
6
>>> li[-1]
'f'
>>> li = ['a', 'b', 'c']
>>> li.append(['d', 'e', 'f']) ***3***
>>> li
['a', 'b', 'c', ['d', 'e', 'f']]
>>> len(li)                    ***4***
4
>>> li[-1]
['d', 'e', 'f']

***1*** Les listes ont deux méthodes, extend et append, qui semblent faire la même chose, mais sont en fait complètement différentes. extend prend un seul argument, qui est toujours une liste et ajoute chacun des éléments de cette liste à la liste originelle.
***2*** Ici nous avons une liste de trois éléments ('a', 'b' et 'c') et nous utilisons extended pour lui ajouter une liste de trois autres éléments ('d', 'e' et 'f'), ce qui nous donne une liste de six éléments.
***3*** Par contre, append prend un argument, qui peut être de n'importe quel type et l'ajoute simplement à la fin de la liste. Ici, nous appelons append avec un argument, qui est une liste de trois éléments.
***4*** Maintenant, la liste originelle qui avait trois éléments en contient quatre. Pourquoi quatre ? Parce que le dernier élément que nous venons d'ajouter est lui-même une liste. Les listes peuvent contenir n'importe quel type de données, y compris d'autres listes. En fonction du but recherché, faites attention de ne pas utiliser append si vous pensez en fait à extend.

III-B-C. Recherche dans une liste

Exemple 3.12. Recherche dans une liste
 
Sélectionnez
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.index("example") ***1***
5
>>> li.index("new")     ***2***
2
>>> li.index("c")       ***3***
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
ValueError: list.index(x): x not in list
>>> "c" in li           ***4***
False

***1*** index trouve la première occurrence d'une valeur dans la liste et retourne son indice. ***2*** index trouve la première occurrence d'une valeur dans la liste. Dans ce cas, new apparaît à deux reprises dans la liste, li[2] et li[6], mais index ne retourne que le premier indice, 2. ***3*** Si la valeur est introuvable dans la liste, Python déclenche une exception. C'est sensiblement différent de la plupart des autres langages qui retournent un indice invalide. Si cela peut sembler gênant, c'est en fait une bonne chose car cela signifie que votre programme se plantera à la source même du problème plutôt qu'au moment ou vous tenterez de manipuler l'indice non valide. ***4*** Pour tester la présence d'une valeur dans la liste, utilisez in, qui retourne True si la valeur a été trouvée et False dans le cas contraire.

Avant la version 2.2.1, Python n'avait pas de type booléen. Pour compenser cela, Python acceptait pratiquement n'importe quoi dans un contexte requérant un booléen (comme une instruction if), en fonction des règles suivantes :
  • 0 est faux, tous les autres nombres sont vrai.
  • Une chaîne vide ("") est faux, toutes les autres chaînes sont vrai.
  • Une liste vide ([]) est faux, toutes les autres listes sont vrai.
  • Un tuple vide (()) est faux, tous les autres tuples sont vrai.
  • Un dictionnaire vide ({}) est faux, tous les autres dictionnaires sont vrai.


Ces règles sont toujours valides en Python 2.3.3 et au-delà, mais vous pouvez maintenant utiliser un véritable booléen, qui a pour valeur True ou False. Notez la majuscule, ces valeurs comme tout le reste en Python, sont sensibles à la casse.

III-B-D. Suppression d'éléments d'une liste

Exemple 3.13. Enlever des éléments d'une liste
 
Sélectionnez
>>> li
['a', 'b', 'new', 'mpilgrim', 'z', 'example', 'new', 'two', 'elements']
>>> li.remove("z")   ***1***
>>> li
['a', 'b', 'new', 'mpilgrim', 'example', 'new', 'two', 'elements']
>>> li.remove("new") ***2***
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two', 'elements']
>>> li.remove("c")   ***3***
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
ValueError: list.remove(x): x not in list
>>> li.pop()         ***4***
'elements'
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two']

***1*** remove enlève la première occurrence de la valeur de la liste.
***2*** remove enlève uniquement la première occurence de la valeur. Dans ce cas, new apparaît à deux reprises dans la liste mais li.remove("new") a seulement retiré la première occurrence.
***3*** Si la valeur est introuvable dans la liste, Python déclenche une exception. Ce comportement est identique à celui de la méthode index.
***4*** pop est un spécimen intéressant. Il fait deux choses : il enlève le dernier élément de la liste et il retourne la valeur qui a été enlevé. Notez que cela diffère de li[-1] qui retourne une valeur mais ne modifie pas la liste et de li.remove(valeur) qui altère la liste mais ne retourne pas de valeur.

III-B-E. Utilisation des opérateurs de listes

Exemple 3.14. Opérateurs de listes
 
Sélectionnez
>>> li = ['a', 'b', 'mpilgrim']
>>> li = li + ['example', 'new'] ***1***
>>> li
['a', 'b', 'mpilgrim', 'example', 'new']
>>> li += ['two']                ***2***
>>> li
['a', 'b', 'mpilgrim', 'example', 'new', 'two']
>>> li = [1, 2] * 3              ***3***
>>> li
[1, 2, 1, 2, 1, 2]

***1*** Les listes peuvent être concaténées à l'aide de l'opérateur +. liste = liste + autreliste est équivalent à list.extend(autreliste). Mais l'opérateur + retourne une nouvelle liste concaténée comme une valeur alors que extend modifie une liste existante. Cela implique que extend est plus rapide, surtout pour de grandes listes.
***2*** Python supporte l'opérateur +=. li += ['two'] est équivalent à li = li + ['two']. L'opérateur += fonctionne pour les listes, les chaînes et les entiers. Il peut être surchargé pour fonctionner également avec des classes définies par l'utilisateur (nous en apprendrons plus sur les classes au Chapitre 5).
***3** L'opérateur * agit sur les liste comme un répéteur. li = [1, 2] * 3 est équivalent à li = [1, 2] + [1, 2] + [1, 2], qui concatène les trois listes en une seule.

Pour en savoir plus sur les listes

III-C. Présentation des tuples

Un tuple (n-uplet) est une liste non-mutable. Un fois créé, un tuple ne peut en aucune manière être modifié.

Exemple 3.15. Définition d'un tuple

 
Sélectionnez
>>> t = ("a", "b", "mpilgrim", "z", "example") ***1***
>>> t
('a', 'b', 'mpilgrim', 'z', 'example')
>>> t[0]                                       ***2***
'a'
>>> t[-1]                                      ***3***
'example'
>>> t[1:3]                                     ***4***
('b', 'mpilgrim')

***1*** Un tuple est défini de la même manière qu'une liste sauf que l'ensemble d'éléments est entouré de parenthèses plutôt que de crochets.
***2*** Les éléments d'un tuple ont un ordre défini, tout comme ceux d'une liste. Les indices de tuples débutent à zéro, tout comme ceux d'une liste, le premier élément d'un tuple non vide est toujours t[0].
***3*** Les indices négatifs comptent à partir du dernier élément du tuple, tout comme pour une liste.
***4***Le découpage fonctionne aussi, tout comme pour une liste. Notez que lorsque vous découpez une liste, vous obtenez une nouvelle liste, lorsque vous découpez un tuple, vous obtenez un nouveau tuple.

Exemple 3.16. Les tuples n'ont pas de méthodes

 
Sélectionnez
>>> t
('a', 'b', 'mpilgrim', 'z', 'example')
>>> t.append("new")    ***1***
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'append'
>>> t.remove("z")      ***2***
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'remove'
>>> t.index("example") ***3***
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
AttributeError: 'tuple' object has no attribute 'index'
>>> "z" in t           ***4***
True

***1*** Vous ne pouvez pas ajouter d'élément à un tuple. Les tuples n'ont pas de méthodes append ou extend.
***2*** Vous ne pouvez pas enlever d'éléments d'un tuple. Les tuples n'ont pas de méthodes remove ou pop.
***3*** Vous ne pouvez pas rechercher d'éléments dans un tuple. Les tuples n'ont pas de méthode index.
***4*** Vous pouvez toutefois utiliser in pour vérifier l'existence d'un élément dans un tuple.

Mais à quoi servent donc les tuples ?

  • Les tuples sont plus rapides que les listes. Si vous définissez un ensemble constant de valeurs et que tout ce que vous allez faire est le parcourir, utilisez un tuple au lieu d'une liste.
  • Votre code est plus sûr si vous «protégez en écriture» les données qui n'ont pas besoin d'être modifiées. Utiliser un tuple à la place d'une liste revient à avoir une assertion implicite que les données sont constantes et que des mesures spécifiques sont nécéssaires pour modifier cette définition.
  • Vous vous souvenez que j'avais dit que que les clés de dictionnaire pouvaient être des entiers, des chaînes et «quelques autres types» ? Les tuples sont un de ces types. Ils peuvent être utilisé comme clé dans un dictionnaire, ce qui n'est pas le cas des listes. En fait, c'est plus compliqué que ça. Les clés de dictionnaire doivent être non-mutables. Les tuples sont non-mutables mais si vous avez un tuple contenant des listes, il est considéré comme mutable et n'est pas utilisable comme clé de dictionnaire. Seuls les tuples de chaînes, de nombres ou d'autres tuples utilisable comme clé peuvent être utilisés comme clé de dictionnaire.
  • Les tuples sont utilisés pour le formatage de chaînes, comme nous le verrons bientôt.

Les tuples peuvent être convertis en listes et vice-versa. La fonction prédéfinie tuple prends une liste et retourne un tuple contenant les mêmes éléments et la fonction list prends un tuple et retourne une liste. En fait, tuple gèle une liste et list dégèle un tuple.

Pour en savoir plus sur les tuples

III-D. Définitions de variables

Maintenant que vous pensez tout savoir à propos des dictionnaires, des tuples et des listes (hum!), revenons à notre programme d'exemple du Chapitre 2, odbchelper.py.
Python dispose de variables locales et globales comme la plupart des autres langages, mais il n'a pas de déclaration explicite des variables. Les variables viennent au monde en se voyant assigner une valeur et sont automatiquement détruites lorsqu'elles se retrouvent hors de portée.

Exemple 3.17. Définition de la variable myParams

 
Sélectionnez
if __name__ == "__main__":
    myParams = {"server":"mpilgrim", \
                "database":"master", \
                "uid":"sa", \
                "pwd":"secret" \
                }

Il y a plusieurs points intéressants ici. Tout d'abord, notez l'indentation. Une instruction if est un bloc de code et nécessite d'être indenté tout comme une fonction.
Deuxièmement, l'assignation de variable est une commande étalée sur plusieurs lignes avec une barre oblique («\») servant de marque de continuation de ligne.

Lorsq'une commande est étalée sur plusieurs lignes avec le marqueur de continuation de ligne («\»), les lignes suivantes peuvent être indentées de n'importe qu'elle manière, les règles d'indentation strictes habituellement utilisées en Python ne s'appliquent pas. Si votre IDE Python indente automatiquement les lignes continuées, vous devriez accepter ses réglages par défauts sauf raison impérative.

Les expressions entre parenthèses, crochets ou accolades (comme la définition d'un dictionnaire) peuvent être réparties sur plusieurs lignes avec ou sans le caractère de continuation («\»). Je préfère inclure la barre oblique même lorsqu'elle n'est pas requise car je pense que cela rends le code plus lisible mais c'est une question de style.

Troisièmement, vous n'avez jamais déclaré la variable myParams, vous lui avez simplement assigné une valeur. C'est comme en VBScript sans l'option option explicit. Heureusement, à l'inverse de VBScript, Python ne permet pas de référencer une variable à laquelle aucune valeur n'a été assigné. Tenter de le faire déclenchera une exception.

III-D-2. Référencer des variables

Exemple 3.18. Référencer une variable non assignée
 
Sélectionnez
>>> x
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
NameError: There is no variable named 'x'
>>> x = 1
>>> x
1

Un jour, vous remercierez Python pour ça.

III-D-3. Assignation simultanée de plusieurs valeurs

Un des raccourcis les plus réjouissants existant en Python est l'utilisation de séquences pour assigner plusieurs valeurs en une fois.

Exemple 3.19. Assignation simultanée de plusieurs valeurs
 
Sélectionnez
>>> v = ('a', 'b', 'e')
>>> (x, y, z) = v     1
>>> x
'a'
>>> y
'b'
>>> z
'e'

***1*** v est un tuple de trois éléments et (x, y, z) est un tuple de trois variables. Le fait d'assigner l'un à l'autre assigne chacune des valeurs de v a chacune des variables, dans leur ordre respectif.

Ce type d'assignation a de multiples usages. Je souhaite souvent assigner des noms a une série de valeurs. En C, vous utiliseriez enum et vous listeriez manuellement chaque constante et la valeur associée, ce qui semble particulièrement fastidieux lorsque les valeurs sont consécutives. En Python, vous pouvez utiliser la fonction prédéfinie range avec l'assignation multiples de variables pour assigner rapidement des valeurs consécutives.

Exemple 3.20. Assignation de valeurs consécutives
 
Sélectionnez
>>> range(7)                                                                    ***1***
[0, 1, 2, 3, 4, 5, 6]
>>> (MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY) = range(7) ***2***
>>> MONDAY                                                                      ***3***
0
>>> TUESDAY
1
>>> SUNDAY
6

***1*** La fonction prédéfinie range retourne une liste d'entiers. Dans sa forme la plus simple, elle prends une borne supérieure et retourne une séquence démarrant à 0 mais n'incluant pas la borne supérieure. (Si vous le souhaitez, vous pouvez spécifier une borne inférieure différente de 0 ou un pas d'incrément différent de 1. Vous pouvez faire un print range.__doc__ pour de plus amples détails.)
***2*** MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY et SUNDAY sont les variables que nous définissons (cet exemple provient du module calendar, qui est un petit module amusant qui affiche des calendriers comme le programme cal sous UNIX. Le module calendar défini des constantes entières pour les jours de la semaine).
***3*** A présent, chaque variable possède sa valeur : MONDAY vaut 0, TUESDAY vaut 1 et ainsi de suite.

Vous pouvez aussi utiliser l'assignation multiple pour créer des fonctions qui retournent plusieurs valeurs, simplement en retournant un tuple contenant ces valeurs. L'appelant peut le traiter en tant que tuple ou assigner les valeurs à différentes variables. Beaucoup de bibliothèques standard de Python font cela, y compris le module os dont nous traiterons au Chapitre 6.

Pour en savoir plus sur les variables

III-E. Formatage de chaînes

Python supporte le formatage de valeurs en chaînes de caractères. Bien que cela peut comprendre des expression très compliquées, l'usage le plus simple consiste à insérer des valeurs dans des chaînes à l'aide de marques %s.

Le formatage de chaînes en Python utilise la même syntaxe que la fonction C sprintf.

Exemple 3.21. Présentation du formatage de chaînes

 
Sélectionnez
>>> k = "uid"
>>> v = "sa"
>>> "%s=%s" % (k, v) ***1***
'uid=sa'

***1*** L'expression entière est évaluée en chaîne. Le premier %s est remplacé par la valeur de k, le second %s est remplacé par la valeur de v. Tous les autres caractères de la chaînes (le signe d'égalité dans le cas présent) restent tels quels.

Notez que (k, v) est un tuple. Je vous avais dit qu'ils servaient à quelque chose.
Vous pourriez pensez que cela représente beaucoup d'efforts pour le formatage de chaîne se bornait à la concaténation. Il n'y est pas question uniquement de formatage mais également de conversion de types.

III-E-2. Exemple 3.22. Formatage de chaîne et concaténation

 
Sélectionnez
>>> uid = "sa"
>>> pwd = "secret"
>>> print pwd + " is not a good password for " + uid      ***1***
secret is not a good password for sa
>>> print "%s is not a good password for %s" % (pwd, uid) ***2***
secret is not a good password for sa
>>> userCount = 6
>>> print "Users connected: %d" % (userCount, )           ***3*** ***4***
Users connected: 6
>>> print "Users connected: " + userCount                 ***5***
Traceback (innermost last):
  File "<interactive input>", line 1, in ?
TypeError: cannot concatenate 'str' and 'int' objects

***1*** + est l'opérateur de concaténation de chaînes. ***2*** Dans ce cas trivial, le formatage de chaînes mène au même résultat que la concaténation. ***3*** (userCount, ) est un tuple contenant un seul élément. Oui, la syntaxe est un peu étrange mais il y a un excellente raison : c'est un tuple sans ambiguité aucune. En fait, vous pouvez toujours mettre une virgule après l'élément terminal lors de la définition d'une liste, d'un tuple ou d'un dictionnaire mais cette virgule est obligatoire lors de la définition d'un tuple avec un élément unique. Si ce n'était pas le cas, Python ne pourrait distinguer si (userCount) est un tuple avec un seul élément ou juste la valeur userCount. ***4*** Le formatage de chaîne fonctionne également avec des entiers en spécifiant %d au lieu de %s. ***5*** Si vous tentez de concaténer une chaîne avec un autre type, Python va déclencher une exception. Au contraire du formatage de chaîne, la concaténation ne fonctionne que si tout les objets sont déjà de type chaîne.

Comme la fonction printf en C, le formatage de chaînes en Python est un véritable couteau suisse. Il y a des options à profusion et des modificateurs de format spécifiques pour de nombreux types de valeurs.

Exemple 3.23. Formatage de nombres

 
Sélectionnez
>>> print "Today's stock price: %f" % 50.4625   ***1***
50.462500
>>> print "Today's stock price: %.2f" % 50.4625 ***2***
50.46
>>> print "Change since yesterday: %+.2f" % 1.5 ***3***
+1.50

***1*** L'option de formatage %f considère la valeur comme un nombre décimal et l'affiche avec six chiffres après la virgule. ***2*** Le modificateurs ".2" de l'option %f tronque la valeur à deux chiffres après la virgule. ***3*** On peut également combiner les modificateurs. Ajouter le modificateur + affiche le signe positif ou négatif avant la valeur. Notez que le modificateur ".2" est toujours en place et qu'il formate la valeur avec exactement deux chiffres après la virgule.

Pour en savoir plus sur le formatage de liste

III-F. Mutation de listes

Une des caractéristiques les plus puissantes de Python est la list comprehension (création fonctionnelle de listes) qui fournit un moyen concis d'appliquer une fonction sur chaque élément d'une liste afin d'en produire une nouvelle.

Exemple 3.24. Présentation des list comprehensions

 
Sélectionnez
>>> li = [1, 9, 8, 4]
>>> [elem*2 for elem in li]      ***1***
[2, 18, 16, 8]
>>> li                           ***2***
[1, 9, 8, 4]
>>> li = [elem*2 for elem in li] ***3***
>>> li
[2, 18, 16, 8]

***1*** Pour comprendre cette ligne, observez là de droite à gauche. li est la liste que vous appliquez. Python la parcourt un élément à la fois, en assignant temporairement la valeur de chacun des éléments à la variable elem. Python applique ensuite la fonction elem*2 et ajoute le résultat à la liste retournée.
***2*** Notez que les list comprehensions ne modifient pas la liste initiale.
***3*** Vous pouvez assigner le résultat d'une list comprehension à la variable que vous traitez. Python assemble la nouvelle liste en mémoire et assigne le résultat à la variable une fois la transformation terminée.

Voici les list comprehensions dans la fonction buildConnectionString que nous avons déclaré au Chapitre 2:

 
Sélectionnez
["%s=%s" % (k, v) for k, v in params.items()]

Notez tout d'abord que vous appelez la fonction items du dictionnaire params. Cette fonction retourne une liste de tuples avec toutes les données stockées dans le dictionnaire.

Exemple 3.25. Les fonctions keys, values et items

 
Sélectionnez
>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
>>> params.keys()   ***1***
['server', 'uid', 'database', 'pwd']
>>> params.values() ***2***
['mpilgrim', 'sa', 'master', 'secret']
>>> params.items()  ***3***
[('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]

***1*** La méthode keys d'un dictionnaire retourne la liste de toutes les clés. Cette liste ne suit pas l'ordre dans lequel le dictionnaire a été défini (souvenez-vous, les éléments d'un dictionnaire ne sont pas ordonnés) mais cela reste une liste.
***2*** La méthode values retourne la liste de toutes les valeurs. La liste est dans le même ordre que celle retournée par keys, on a donc params.values()[n] == params[params.keys[n]] pour toute valeur de n.
***3*** La méthode items retourne une liste de tuples de la forme (clé, valeur). La liste contient toutes les données stockées dans le dictionnaire.

Voyons maintenant ce que fait buildConnectionString. Elle prends une liste, param.items(), et crée une nouvelle liste en appliquant une instruction de formatage de chaîne à chacun de ses éléments. La nouvelle liste aura le même nombre d'éléments que params.items() mais chaque élément sera une chaîne qui contient à la fois une clé et la valeur qui lui est associée dans le dictionnaire params.

Exemple 3.26. List comprehensions dans buildConnectionString, pas à pas

 
Sélectionnez
>>> params = {"server":"mpilgrim", "database":"master", "uid":"sa", "pwd":"secret"}
>>> params.items()
[('server', 'mpilgrim'), ('uid', 'sa'), ('database', 'master'), ('pwd', 'secret')]
>>> [k for k, v in params.items()]                ***1***
['server', 'uid', 'database', 'pwd']
>>> [v for k, v in params.items()]                ***2***
['mpilgrim', 'sa', 'master', 'secret']
>>> ["%s=%s" % (k, v) for k, v in params.items()] ***3***
['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']

***1*** Notez que nous utilisons deux variables pour parcourir la liste params.items(). Il s'agit d'un autre usage de l'assignment multiple. Le premier élément de params.items() est ('server', 'mpilgrim'), donc lors de la première itération de la transformation, k va prendre la valeur 'server' et v la valeur 'mpilgrim'. Dans ce cas, nous ignorons la valeur de v et placons uniquement la valeur de k dans la liste résultante. Cette transformation correspond donc au comportement de params.keys(). (Vous n'utiliseriez pas réellement une list comprehension comme ceci dans du vrai code; il s'agit d'un exemple exagérément simple pour que vous compreniez ce qui se passe.)
***2*** Nous faisons la même chose ici, mais nous ignorons la valeur de k de telle sorte que le résultat est équivalent à celui de params.values().
***3*** En combinant les deux exemples précédent avec le formatage de chaîne, nous obtenons une liste de chaînes comprenant la clé et la valeur de chaque élément du dictionnaire. Cela ressemble étonnament à la sortie du programme, tout ce qui reste à faire maintenant est la jointure des éléments de cette liste en une seule chaîne.

Pour en savoir plus sur les list comprehensions

III-G. Jointure de listes et découpage de chaînes

Nous avons une liste de paires clé-valeur sous la forme clé=valeur et nous voulons les assembler au sein d'une même chaîne. Pour joindre une liste de chaînes en une seule, nous pouvons utiliser la méthode join d'un objet chaîne.
Voici un exemple de jointure de liste provenant de la fonction buildConnectionString :

 
Sélectionnez
    return ";".join(["%s=%s" % (k, v) for k, v in params.items()])

Une remarque intéressante avant de continuer. Je ne cesse de répéter que les fonctions sont des objets, que les chaînes sont des objets, que tout est objet. Vous pourriez penser que seules les variables de type chaîne sont des objets. Mais ce n'est pas le cas, regardez de plus près cet exemple et vous verrez que la chaîne ";" est elle même un objet dont vous appelez la méthode join.

La méthode join assemble les éléments d'une liste pour former une chaîne unique, chaque élément étant séparé par un point virgule. Le séparateur n'est pas forcément un point-virgule, il n'est même pas forcément un caractère unique. Il peut être n'importe quelle chaîne.

La méthode join ne fonctionne qu'avec des listes de chaînes; elle n'applique pas la conversion de types. La jointure d'une liste comprenant au moins un élément non-chaîne déclenchera une exception.

III-G-1. Exemple 3.28. Découpage d'une chaîne

 
Sélectionnez
>>> li = ['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
>>> s = ";".join(li)
>>> s
'server=mpilgrim;uid=sa;database=master;pwd=secret'
>>> s.split(";")    ***1***
['server=mpilgrim', 'uid=sa', 'database=master', 'pwd=secret']
>>> s.split(";", 1) ***2***
['server=mpilgrim', 'uid=sa;database=master;pwd=secret']

***1*** split fait l'inverse de join en découpant une chaîne en une liste de plusieurs éléments. Notez que le délimiteur («;») est totalement supprimé, il n'apparaît dans aucun des éléments de la liste retournée. ***2*** split prend en deuxième argument optionnel le nombre de découpages à effectuer («Des arguments optionnels ?» Vous apprendrez à en définir dans vos propres fonctions au prochain chapitre.)

une_chaîne.split(delimiteur, 1) est une technique utile pour chercher une sous-chaîne dans une chaîne et utiliser tout ce qui précède cette sous-chaîne (le premier élément de la liste retournée) et tout ce qui la suit (le second élément de la liste retournée).

Pour en savoir plus sur les méthodes de chaînes

III-G-2. Note historique sur les méthodes de chaînes

Lorsque j'ai débuté l'apprentissage de Python, je m'attendais à ce que join soit une méthode de liste qui aurait pris un séparateur comme argument. Beaucoup de gens pensent la même chose et il y a une véritable histoire derrière la méthode join. Avant Python 1.6, les chaînes n'étaient pas pourvue de toutes ces méthodes si utiles. Il y avait un module string séparé qui contenait toutes les fonctions de manipulation de chaînes de caractères, chacune prenant une chaîne comme premier argument. Ces fonctions ont été considérées assez importantes pour être intégrées dans les chaînes elles même, ce qui semblait logique pour des fonctions comme lower, upper et split. Mais beaucoup de programmeurs Python issus du noyau dur émirent des objections quant à la méthode join en arguant du fait qu'elle devrait être plutôt une méthode de liste ou tout simplement rester une fonction du module string (qui contient encore bien des choses utiles). J'utilise exclusivement la nouvelle méthode join mais vous verrez du code écrit des deux façons et si cela vous pose un réel problème, vous pouvez toujours opter pour l'ancienne fonction string.join.

III-H. Résumé

A présent, le programme odbchelper.py et sa sortie devraient vous paraître parfaitement clairs.

 
Sélectionnez
def buildConnectionString(params):
    """Build a connection string from a dictionary of parameters.

    Returns string."""
    return ";".join(["%s=%s" % (k, v) for k, v in params.items()])

if __name__ == "__main__":
    myParams = {"server":"mpilgrim", \
                "database":"master", \
                "uid":"sa", \
                "pwd":"secret" \
                }
    print buildConnectionString(myParams)

Voici la sortie de odbchelper.py:

 
Sélectionnez
server=mpilgrim;uid=sa;database=master;pwd=secret

Avant de vous plonger dans le chapitre suivant, assurez vous que vous vous sentez à l'aise pour :

  • Utiliser l'IDE Python pour tester des expressions de manière interactive
  • Ecrire des modules Python et les exécuter depuis votre IDE ou en ligne de commande
  • Importer des modules et appeler leurs fonctions
  • Déclarer des fonctions et utiliser des doc string, des variables locales et une indentation correcte
  • Définir des dictionnaires, des tuples et des listes
  • Accéder aux attributs et méthodes de tout objet, y compris les chaînes, les listes, les dictionnaires, les fonctions et les modules
  • Concaténer des valeur avec le formatage de chaînes
  • Utiliser les lists comprehensions pour la mutation de listes
  • Découper des chaînes en listes et joindre des listes en chaînes

précédentsommairesuivant