Plongée dans Python


précédentsommaire

III. Chapitre 2 – Les types de données natifs

  • « L’émerveillement est le fondement de toute philosophie, l’investigation assure son progrès, l’ignorance entraîne sa fin. » Michel de Montaigne

III-A. Plongeons

Les types de données : Mettez un instant de côté votre premier programme Python, et parlons un peu types de données. En Python, toute valeur a un type, mais vous n’êtes pas obligé de déclarer le type des variables. Comment est-ce possible ? En se basant sur l’affectation initiale d’une valeur à une variable, Python déduit le type de la variable et en garde trace en interne.

Python a de nombreux types de données natifs. Voici les plus importants :

  1. Les booléens (booleans) sont vrais ou faux (valeurs True ou False).
  2. Les nombres (numbers) peuvent être des entiers (1 et 2), des nombres à virgule flottante (1.1 et 1.3) des fractions (1/2 et 2/3) ou même des nombres complexes.
  3. Les chaînes (strings en anglais et en Python) sont des séquences de caractères Unicode, par exemple un document HTML.
  4. Les octets et les tableaux d’octets représentent par exemple une image JPEG.
  5. Les listes sont des séquences ordonnées de valeurs.
  6. Les tuples sont des séquences ordonnées mais immuables de valeurs.
  7. Les sets ou ensembles sont des conteneurs de valeurs en vrac.
  8. Les dictionnaires sont des ensembles non ordonnés de paires clé-valeur.

Il y a bien entendu plus de types que cela. Tout est objet en Python, ainsi y a-t-il des types comme module, function, class, method, file (fichier), et même compiled code (code compilé). Vous en avez déjà rencontré certains : les modules ont des noms, les fonctions ont des docstrings, etc. Vous en apprendrez davantage sur les classes dans le chapitre Classes et itérateurs, et à propos des fichiers dans le chapitre Fichiers.

Les chaînes et les octets sont suffisamment importants et compliqués pour avoir droit à des chapitres dédiés. Voyons d’abord les autres.

III-B. Les booléens

Vous pouvez utiliser pour ainsi dire n’importe quelle expression dans un contexte booléen.

Un booléen est soit vrai, soit faux. Python possède deux constantes, astucieusement dénommées True (vrai) et False (faux), qui peuvent être utilisées pour assigner directement des valeurs booléennes. Des expressions peuvent également être évaluées comme des valeurs booléennes. À certains endroits (comme dans les instructions if), Python s’attend à ce qu’une expression soit évaluée comme une valeur booléenne. Ces endroits sont appelés des contextes booléens. Vous pouvez utiliser pour ainsi dire n’importe quelle expression dans un contexte booléen, et Python essaiera de déterminer si sa valeur est vraie. Les différents types de données ont des règles différentes pour déterminer quelles valeurs sont vraies ou fausses dans un contexte booléen. (Cela vous paraîtra plus clair quand vous aurez vu quelques exemples concrets plus loin dans ce chapitre.)

Comme exemple, prenez ce bout de code de humansize.py :

 
Sélectionnez

If size<0 :

  raise ValueError(‘le nombre ne doit pas être négatif’)

size est un entier, 0 est un entier, et < est un opérateur numérique. Le résultat de l’expression size < 0 est toujours un booléen. Vous pouvez vérifier cela vous-même dans le shell interactif de Python :

 
Sélectionnez
>>> size=1
>>> size<0
False
>>> size=0
>>> size<0
False
>>> size=-1
>>> size<0
True

Suite à un héritage laissé par Python 2, les booléens peuvent être manipulés comme des nombres. True correspond à 1 ; False correspond à 0.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
>>> True + True
2
>>> True - False
1
>>> True * False
0
>>> True / False
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
ZeroDivisionError: int division or modulo by zero

Aïe, aïe, aïe ! Ne faites jamais ça ! Oubliez que j’y ai même seulement fait allusion !

III-C. Les nombres

Les nombres sont impressionnants. Il y a un tel choix ! Python supporte à la fois les entiers et les nombres en virgule flottante. Et il n’y a pas de déclaration de type pour les distinguer ; Python fait la différence en fonction de la présence ou de l’absence du point décimal.

 
Sélectionnez
>>> type(1)            (1)
<class 'int'>
>>> isinstance(1,int)    (2)
True
>>> 1+1            (3)
2
>>> 1+1.0            (4)
2.0
>>> type(2.0)
<class 'float'>

NdlR : les notations (1), (2), etc. ne font pas partie du code.

(1) Vous pouvez utiliser la fonction type() pour vérifier le type de n’importe quelle valeur ou variable. Comme vous vous en doutiez, 1 est un entier (int).

(2) De même, vous pouvez utiliser la fonction isinstance() pour vérifier si une valeur ou une variable est d’un type donné.

(3) Ajouter un entier (int) à un entier donne un entier.

(4) Ajouter un entier (int) à un flottant (float) donne un flottant. Python force la conversion de l'entier en flottant, puis retourne le résultat de l'addition dans un flottant.

III-C-1. Convertir des entiers en flottants et vice-versa

Comme vous venez de le voir, certains opérateurs (comme l’addition) vont convertir les entiers en flottants selon les besoins. Vous pouvez aussi les convertir vous-même.

 
Sélectionnez
>>> float(2)            (1)
2.0
>>> int(2.0)            (2)
2
>>> int(2.5)            (3)
2
>>> int(-2.5)            (4)
-2
>>> 1.12345678901234567890    (5)
1.1234567890123457
>>> type(1000000000000000)    (6)
<class 'int'>

(1) Vous pouvez explicitement convertir un entier en un flottant avec la fonction float().

(2) Sans surprise, vous pouvez aussi convertir un flottant en un entier avec la fonction int().

(3) La fonction int() va tronquer le nombre et non l’arrondir.

(4) La fonction int() tronque les nombres négatifs en allant vers 0. Il s’agit d’une vraie fonction de troncature, non d’une mise à zéro de la partie décimale.

(5) Les nombres à virgule flottante ont une précision jusqu’à la quinzième décimale.

  1. Les entiers peuvent être arbitrairement grands.

Python 2 possédait deux types d’entiers séparés int et long. Le type int était limité à kitxmlcodeinlinelatexdvp2^32-1finkitxmlcodeinlinelatexdvp. Python 3 ne possède qu’un seul type d’entier qui se comporte essentiellement comme le type long de Python 2. Pour plus de précisions, voir PEP 237.

III-C-2. Opérations numériques courantes

Vous pouvez faire toutes sortes de choses avec les nombres.

 
Sélectionnez
>>> 11/2        (1)
5.5
>>> 11//2        (2)
5
>>> -11//2        (3)
-6
>>> 11.0//2        (4)
5.0
>>> 11**2        (5)
121
>>> 11%2        (6)
1

(1) L’opérateur / effectue des divisions en virgule flottante. Même si le numérateur et le dénominateur sont des entiers, le résultat sera un nombre en virgule flottante (float).

(2) L’opérateur // effectue des divisions entières un peu particulières. Quand le résultat est positif, vous pouvez le considérer comme une troncature (non un arrondi) à 0 décimales, mais considérez ceci avec prudence.

(3) En effectuant une division entière d’un entier négatif, l’opérateur // arrondit par excès au plus proche entier. Mathématiquement parlant, il arrondit par défaut étant donné que -6 est plus petit que -5, mais si vous attendez un arrondi à -5 cela pourrait vous désarçonner.

(4) L’opérateur // ne retourne pas toujours un entier. Si soit le numérateur, soit le dénominateur est un flottant (float), il arrondit quand même à l’entier le plus proche, mais la valeur retournée sera un flottant.

(5) L’opérateur ** signifie « élevé à la puissance ». 112 donne 121.

(6) L’opérateur % retourne le reste de la division entière. 11 divisé par 2 est égal à 5 reste 1. Le résultat est donc 1.

En Python 2, l’opérateur / correspondait à une division entière. Mais vous pouviez en changer le comportement de façon à obtenir une division en virgule flottante en incluant une directive spéciale dans le code source. Dans Python 3, l’opérateur correspond toujours à une division en virgule flottante. Voir PEP 238 pour plus de détails.

III-C-3. Fractions

Python n’est pas limité aux nombres entiers et aux nombres en virgule flottante. Il peut aussi faire toutes les mathématiques imaginables que vous avez apprises au lycée et que vous vous êtes promptement empressé d’oublier.

 
Sélectionnez
>>> import fractions            (1)
>>> x=fractions.Fraction(1,3)          (2)
>>> x
Fraction(1, 3)
>>> x*2                    (3)
Fraction(2, 3)
>>> fractions.Fraction(6,4)        (4)
Fraction(3, 2)
>>> fractions.Fraction(0,0)        (5)
Traceback (most recent call last):
  File "<pyshell#5>", line 1, in <module>
    fractions.Fraction(0,0)
  File "C:\Users\ercamos\AppData\Local\Programs\Python\Python35\lib\fractions.py", line 186, in __new__
    raise ZeroDivisionError('Fraction(%s, 0)' % numerator)
ZeroDivisionError: Fraction(0, 0)

(1) Pour utiliser les fractions, commencez par importer le module fractions.

(2) Pour définir une fraction, créez un objet Fraction en lui passant le numérateur et le dénominateur comme arguments.

(3) Vous pouvez effectuer toutes les opérations mathématiques usuelles avec les fractions. Les opérations retournent un nouvel objet de type Fraction : 2*(1/3)=(2/3).

(4) L’objet Fraction va automatiquement simplifier les fractions : (6/4)=(3/2).

(5) Python a le bon goût de ne pas créer de fraction avec le dénominateur zéro.

III-C-4. Trigonométrie

Vous pouvez aussi faire de la trigonométrie de base avec Python.

 
Sélectionnez
>>> import math
>>> math.pi                (1)
3.141592653589793    
>>> math.sin(math.pi/2)          (2)
1.0
>>> math.tan(math.pi/4)          (3)
0.9999999999999999

(1) Le module math contient la constante π, qui est le rapport de la circonférence d’un cercle à son diamètre.

(2) Le module math contient toutes les fonctions trigonométriques de base, y compris sin(), cos(), tan(), ainsi que des variantes comme asin().

(3) Notez toutefois que Python n’est pas d’une précision infinie, tan(π/4) devrait retourner 1.0 et non 0.9999999999999999.

III-C-5. Les nombres dans un contexte booléen.

Les valeurs à zéro sont False, toutes les autres valeurs sont True.

Vous pouvez utiliser des nombres dans un contexte booléen, par exemple dans une instruction if. Les valeurs zéro valent False (faux) et les valeurs différentes de zéro valent True (vrai).

 
Sélectionnez
>>> def est_ce_vrai(quelquechose):            (1)
    if quelquechose:
        print("oui,c'est vrai")
    else:
        print("non, c'est faux")
        
>>> est_ce_vrai(1)                    (2)
oui,c'est vrai
>>> est_ce_vrai(-1)
oui,c'est vrai
>>> est_ce_vrai(0)
non, c'est faux
>>> est_ce_vrai(0.1)                    (3)
oui,c'est vrai
>>> est_ce_vrai(0.0)
non, c'est faux
>>> import fractions
>>> est_ce_vrai(fractions.Fraction(1,2))        (4)
oui,c'est vrai
>>> est_ce_vrai(fractions.Fraction(0,1))
non, c'est faux

(1) Saviez-vous que vous pouviez définir vos propres fonctions dans le shell interactif de Python ? Appuyez juste sur ENTRÉE à la fin de chaque ligne et deux fois sur ENTRÉE à la fin de la fonction.

(2) Dans un contexte booléen, les valeurs non nulles sont vraies et les valeurs nulles sont fausses.

(3) Les nombres à virgule flottante non nuls sont vrais, 0.0 est faux. Méfiez-vous de ce dernier ! La moindre erreur d’arrondi (ce qui n’est pas du domaine de l’impossible, comme nous l’avons vu dans la section précédente) fera par exemple tester à Python la valeur 0,000000001 au lieu de 0 et il retournera True.

(4) Les fractions aussi peuvent être utilisées dans un contexte booléen. Fraction(0,n) sera faux pour toutes les valeurs de n (sauf 0 bien sûr). Toutes les autres fractions sont vraies.

III-D. Les Listes

Les listes sont les types de données à tout faire de Python. Quand je dis « liste », vous pensez peut-être « tableaux dont je dois définir la taille par avance et qui ne peuvent contenir que des éléments de type identique ». Ne pensez pas ça. Les listes sont bien plus cool que ça.

Une liste en Python est comme un tableau en Perl 5. Sauf qu’en Perl 5 les variables qui contiennent des tableaux commencent par le caractère @, alors qu’en Python les variables peuvent être désignées par un nom quelconque, Python se chargeant de garder en mémoire le type de la variable.

Une liste en Python est bien plus qu’un tableau en Java (bien qu’elle puisse être utilisée en tant que telle si c’est tout ce que vous attendez de la vie). Une meilleure analogie serait la classe ArrayList, qui peut contenir des objets arbitraires et peut s’agrandir dynamiquement au fur et à mesure qu’on y ajoute des éléments.

III-D-1. Créer une liste

Il est facile de créer une liste : utilisez des crochets pour encadrer une liste de valeurs séparées par des virgules.

 
Sélectionnez
>>> a_list=['a','b','mpilgrim','z','example']    (1)
>>> a_list
['a', 'b', 'mpilgrim', 'z', 'example']
>>> a_list[0]                        (2)
'a'
>>> a_list[4]                        (3)
'example'
>>> a_list[-1]                        (4)
'example'
>>> a_list[-3]                        (5)
'mpilgrim'

(1) Tout d’abord, définissez une liste de 5 éléments. Notez que ceux-ci restent dans le même ordre. Une liste est un ensemble ordonné d’éléments.

(2) Une liste peut être utilisée comme un tableau de base 0. Le premier élément de toute liste non vide est toujours a_list[0].

(3) Le dernier élément de cette liste de cinq éléments est a_list[4], parce que les listes sont toujours à base 0.

(4) Un index négatif accède aux éléments à partir de la fin de la liste en comptant à l’envers. Le dernier élément de toute liste non vide est toujours a_list[-1].

(5) Si les index négatifs vous semblent déroutants, pensez-y de la manière suivante : a_list[-1]==a_list[len(a_list)-n]. Donc a_list[-3]==a_list[5-3]==a_list[2].

III-D-2. Découper une liste

Une fois que vous avez défini une liste, vous pouvez en extraire n’importe quelle partie en tant que nouvelle liste. Cela s’appelle découper (slicing en anglais) une liste.

 
Sélectionnez
>>> a_list
['a', 'b', 'mpilgrim', 'z', 'example']
>>> a_list[1:3]            (1)
['b', 'mpilgrim']
>>> a_list[1:-1]            (2)
['b', 'mpilgrim', 'z']
>>> a_list[0:3]            (3)
['a', 'b', 'mpilgrim']
>>> a_list[:3]            (4)
['a', 'b', 'mpilgrim']
>>> a_list[3:]            (5)
['z', 'example']
>>> a_list[:]            (6)
['a', 'b', 'mpilgrim', 'z', 'example']

(1) Vous pouvez extraire une tranche de liste, appelée « slice », en spécifiant deux index. La valeur retournée est une nouvelle liste contenant tous les éléments de la liste, dans l’ordre, en commençant par l’élément ayant le premier index de la tranche (dans notre cas a_list[1]), et finissant par l’élément précédant celui ayant le deuxième index de la tranche (dans notre cas a_list[3], non compris).

(2) Le découpage fonctionne aussi si l’un ou les deux index sont négatifs. Au besoin vous pouvez vous représenter les choses de la façon suivante : en parcourant la liste de gauche à droite, le premier index de la tranche désigne le premier élément dont vous voulez, et le deuxième index de la tranche identifie le premier élément dont vous ne voulez pas. La valeur retournée correspond à tout ce dont vous avez voulu en cours de route.

(3) Les listes sont basées sur 0, ainsi a_list[0,3] renvoie les trois premiers éléments de la liste, en commençant par a_list[0] et en allant jusqu’à a_list[3], mais sans inclure ce dernier.

(4) Si l’index gauche de la tranche est égal à 0, vous pouvez l’omettre et il sera inclus implicitement. Ainsi a_list[:3] est équivalent à a_list[0:3], le 0 étant implicite.

(5) De même, si l’index de droite de la tranche correspond à la longueur de la liste, vous pouvez l’omettre. Ainsi a_list[3:] est équivalent à a_list[3:5], parce que cette liste a 5 éléments. Nous observons ici une amusante symétrie. Dans cette liste de 5 éléments, a_List[:3] retourne les 3 premiers éléments, et a_list[3:] retourne les 2 derniers. En fait a_list[n:] retourne toujours les n premiers éléments et a_list[:n] retourne le reste de la liste, quelle que soit la longueur de la liste.

(6) Si on omet les deux index, tous les éléments de la liste sont inclus. Mais cette liste n’est pas la même que celle du a_list original. Il s’agit d’une nouvelle liste qui contient tous les éléments de l’originale. a_list[:] est un raccourci pour obtenir une copie complète de la liste a_list.

III-D-3. Ajouter des éléments à une liste

Il y a quatre façons d’ajouter des éléments à une liste.

 
Sélectionnez
>>> a_list=['a']
>>> a_list=a_list+[2.0,3]        (1)
>>> a_list                    (2)
['a', 2.0, 3]
>>> a_list.append(True)              (3)
>>> a_list
['a', 2.0, 3, True]
>>> a_list.extend(['four','Ω'])    (4)
>>> a_list
['a', 2.0, 3, True, 'four', 'Ω']
>>> a_list.insert(0,'Ω')        (5)
>>> a_list
['Ω', 'a', 2.0, 3, True, 'four', 'Ω']

(1) L’opérateur + concatène les listes afin de créer une nouvelle liste. Une liste peut contenir un nombre quelconque d’éléments. Il n’y a pas de limite de taille (à part la mémoire disponible). Toutefois, si la taille de la mémoire est cruciale, ayez à l’esprit qu’une concaténation de listes crée une nouvelle liste en mémoire. Dans ce cas, cette nouvelle liste est immédiatement affectée à la variable existante a_list. Le code de concaténation correspond donc en fait à un processus en deux étapes – concaténation puis affectation – ce qui peut consommer (temporairement) pas mal de mémoire si vous travaillez avec des listes de grande taille.

(2) Une liste peut contenir des éléments de n’importe quel type, et les éléments dans une liste unique n’ont pas besoin d’être tous du même type. Nous avons ici une liste qui contient une chaîne, un nombre à virgule flottante et un entier.

(3) La méthode append() ajoute un élément unique à la fin de la liste. Nous avons maintenant quatre types différents dans la liste.

(4) Les listes sont implémentées en tant que classes. « Créer » une liste consiste en fait à instancier une classe. En tant que classe, une liste possède des méthodes qui permettent d’y effectuer des modifications. La méthode extend() prend un seul argument, ici une liste, et ajoute chaque élément de celle-ci à la fin de la liste originale.

(5) La méthode insert() insère un élément unique dans une liste. Le premier argument est l’index du premier élément qui sera éjecté de sa position. Les éléments d’une liste ne doivent pas forcément être uniques, nous avons maintenant deux éléments distincts ayant la valeur 'Ω' : le premier élément, a_list[0], et le deuxième élément, a_list[6].

a_list.insert(0,value) est équivalent à la fonction unshift() en Perl. Elle insère un élément en tête de liste et tous les éléments suivants sont décalés d’une position pour faire de la place.

Voyons de plus près la différence entre append() et extend().

 
Sélectionnez
>>> a_list=['a','b','c']
>>> a_list.extend(['d','e','f'])        (1)
>>> a_list
['a', 'b', 'c', 'd', 'e', 'f']
>>> len(a_list)                    (2)
6
>>> a_list[-1]
'f'
>>> a_list.append(['g','h','i'])        (3)
>>> a_list
['a', 'b', 'c', 'd', 'e', 'f', ['g', 'h', 'i']]
>>> len(a_list)                    (4)
7
>>> a_list[-1]
['g', 'h', 'i']

(1) La méthode extend() prend un seul argument, qui est toujours une liste, et ajoute chaque élément de cette liste à a_list.

(2) Si vous commencez avec une liste de trois éléments, et si vous l’étendez avec une liste de trois éléments supplémentaires, vous obtenez finalement une liste de six éléments.

(3) Par ailleurs, la méthode append() prend un seul argument qui peut être de n’importe quel type. Vous appelez ici la méthode append() avec une liste de trois éléments.

(4) Si vous partez d’une liste de six éléments et que vous y ajoutez une liste de trois éléments, vous vous retrouvez avec une liste …de sept éléments. Pourquoi sept ? Parce que le dernier élément (que vous venez d’ajouter) est lui-même une liste. Les listes peuvent contenir n’importe quels types de données, y compris d’autres listes. C’est peut-être ce que vous vouliez obtenir, ou non. Mais c’est ce que vous avez demandé, et vous l’avez obtenu.

III-D-4. Rechercher des valeurs dans une liste

 
Sélectionnez
>>> a_list=['a','b','new','mpilgrim','new']
>>> a_list.count('new')                      (1)
2
>>> 'new' in a_list                    (2)
True
>>> 'c' in a_list
False
>>> a_list.index('mpilgrim')                (3)
3
>>> a_list.index('new')                      (4)
2
>>> a_list.index('c')                    (5)
Traceback (most recent call last):
  File "<pyshell#6>", line 1, in <module>
    a_list.index('c')
ValueError: 'c' is not in list

(1) Comme vous vous en doutez, la méthode count() renvoie le nombre d’occurrences dans la liste d’une valeur donnée.

(2) Si tout ce que vous voulez savoir est si une valeur est présente ou non dans la liste, l’opérateur in est légèrement plus rapide que la méthode count(). L’opérateur in retourne toujours True ou False, il ne vous dira pas combien de fois la valeur apparaît dans la liste.

(3) Ni l’opérateur in, ni la méthode count(), ne vous diront où se trouve la valeur recherchée. Si vous avez besoin de savoir se trouve la valeur dans la liste, faites appel à la méthode index(). Par défaut elle parcourra toute la liste, mais vous pouvez spécifier un second argument précisant l’endroit de la liste (débutant à 0) où commencer la recherche, et même un troisième argument précisant où arrêter.

(4) La méthode index() retournera la position de la première occurrence de l’argument dans la liste. Dans notre cas, 'new' apparaît deux fois dans la liste, en a_list[2] et en a_list[4], mais la méthode index() ne retournera que l’index de la première occurrence.

(5) Comme vous ne vous en doutez peut-être pas, si elle ne trouve pas la valeur dans la liste, la méthode index() lèvera une exception.

Attendez là, qu’est-ce que vous dites ? La méthode index() lève une exception si elle ne trouve pas la valeur dans la liste. Voilà qui diffère notablement des autres langages, qui retourneront un index invalide (comme -1). Cela peut paraître gênant au premier abord, mais je pense que vous finirez par l’apprécier. Cela signifie que votre programme plantera à la source du problème au lieu d’échouer de façon étrange et silencieuse un peu plus loin. Souvenez-vous que -1 est un index valide. Si la méthode index() retournait -1, cela pourrait mener à des séances de débogage pas très plaisantes.

III-D-5. Retirer des éléments d’une liste

Les listes peuvent s’agrandir et se contracter automatiquement. Nous avons vu la partie extension. Il y a également différentes façons de retirer des éléments d’une liste.

 
Sélectionnez
 >>> a_list=['a','b','new','mpilgrim','new']
>>> a_list[1]
'b'
>>> del a_list[1]            (1)
>>> a_list
['a', 'new', 'mpilgrim', 'new']
>>> a_list[1]            (2)
'new'

(1) Vous pouvez utiliser l’instruction del pour effacer un élément de la liste.

(2) Accéder à l’index 1 après l’avoir effacé ne se conclut pas par une erreur. Tous les éléments situés après l’élément effacé changent d’index positionnel de manière à « boucher les trous ».

Vous ne connaissez pas l’index de position ? Pas de problème, vous pouvez aussi retirer les éléments par valeur.

 
Sélectionnez
>>> a_list.remove('new')    (1)
>>> a_list
['a', 'mpilgrim', 'new']
>>> a_list.remove('new')    (2)
>>> a_list
['a', 'mpilgrim']
>>> a_list.remove('new')
Traceback (most recent call last):
  File "<pyshell#17>", line 1, in <module>
    a_list.remove('new')
ValueError: list.remove(x): x not in list

(1) Vous pouvez aussi retirer un élément de la liste avec la méthode remove(). La méthode remove() prend une valeur en paramètre et retire sa première occurrence de la liste. Encore une fois, les éléments suivants verront leur index décrémenté d’une unité afin de boucher les trous. Les listes ne contiennent jamais de trous.

(2) Vous pouvez appeler la méthode remove() aussi souvent que vous le voulez, mais elle lèvera une exception si elle ne trouve pas la valeur dans la liste.

III-D-6. Retirer des éléments d’une liste : un tour en prime

Une autre méthode intéressante des listes est la méthode pop(). La méthode pop() est encore une autre manière de retirer des éléments d’une liste, mais avec un petit truc en plus.

 
Sélectionnez
>>> a_list=['a','b','new','mpilgrim']
>>> a_list.pop()        (1)
'mpilgrim'
>>> a_list
['a', 'b', 'new']
>>> a_list.pop(1)        (2)
'b'
>>> a_list
['a', 'new']
>>> a_list.pop()
'new'
>>> a_list.pop()
'a'
>>> a_list.pop()        (3)
Traceback (most recent call last):
  File "<pyshell#28>", line 1, in <module>
    a_list.pop()
IndexError: pop from empty list

(1) Quand on l’appelle sans argument, la méthode pop() retire le dernier élément de la liste et en retourne la valeur.

(2) Vous pouvez éjecter un article quelconque de la liste. Il suffit de passer en argument l’index de position de l’élément à retirer. La méthode pop() retire l’élément désigné, puis déplace les éléments suivants afin de boucher les trous, et enfin retourne la valeur de l’élément retiré.

(3) Faire appel à pop() sur une liste vide lève une exception.

Faire appel à la méthode pop() d’une liste sans fournir d’argument est équivalent à la fonction pop() de Perl. Elle retire le dernier élément de la liste et en retourne la valeur. Perl possède une autre fonction, shift(), qui retire le premier élément d’une liste et en retourne la valeur ; en Python cela équivaut à a_list.pop(0).

III-D-7. Les listes dans un contexte booléen

Vous pouvez aussi utiliser la liste dans un contexte booléen, tel qu’une instruction if.

 
Sélectionnez
>>> def est_ce_vrai(quelque_chose):
    if quelque_chose:
        print("oui, c'est vrai")
    else:
        print("non, c'est faux")

        
>>> est_ce_vrai([])        (1)
non, c'est faux
>>> est_ce_vrai(['a'])        (2)
oui, c'est vrai
>>> est_ce_vrai([False])    (3)
oui, c'est vrai

(1) Dans un contexte booléen, une liste vide est fausse.

(2) Toute liste avec au moins un élément est vraie.

(3) Toute liste avec au moins un élément est vraie. La valeur de l’élément est sans importance.

III-E. Les Tuples

Un tuple est une liste immuable. Un tuple ne peut être modifié de quelque façon que ce soit une fois qu’il a été créé.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
>>> a_tuple=('a','b','mpilgrim','z','exemple')    (1)
>>> a_tuple
('a', 'b', 'mpilgrim', 'z', 'exemple')
>>> a_tuple[0]                        (2)
'a'
>>> a_tuple[-1]                        (3)
'exemple'
>>> a_tuple[1:3]                        (4)
('b', 'mpilgrim')

(1) Un tuple est défini de la même façon qu’une liste, sauf que l’ensemble des éléments est compris entre parenthèses au lieu de crochets.

(2) Les éléments d’un tuple sont dans un ordre défini, exactement comme dans une liste. Les index des tuples ont pour base 0, exactement comme les listes, ainsi le premier élément d’un tuple non vide sera toujours a_tuple[0].

(3) Les index négatifs comptent à partir de la fin du tuple, exactement comme dans une liste.

(4) Le découpage (slicing) fonctionne également, exactement comme pour une liste. Quand vous découpez une liste, vous obtenez une nouvelle liste ; quand vous découpez un tuple, vous obtenez un nouveau tuple.

La différence principale entre les tuples et les listes, c’est que les tuples ne peuvent pas être modifiés. En termes techniques, les tuples sont immuables. En termes pratiques, ils ne possèdent pas de méthodes vous permettant de les modifier. Les listes ont des méthodes comme append(), extend(), insert(), remove() et pop(). Les tuples ne possèdent aucune de ces méthodes. Vous pouvez découper un tuple (parce que ça crée un nouveau tuple), et vous pouvez vérifier qu’un tuple contient une certaine valeur (parce que ça ne modifie pas le tuple), et…c’est tout.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
>>> # suite de l'exemple précédent
>>> a_tuple
('a', 'b', 'mpilgrim', 'z', 'exemple')

>>> a_tuple.append('new')        (1)

Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    a_tuple.append('new')
AttributeError: 'tuple' object has no attribute 'append'

>>> a_tuple.remove('z')            (2)

Traceback (most recent call last):
  File "<pyshell#8>", line 1, in <module>
    a_tuple.remove('z')
AttributeError: 'tuple' object has no attribute 'remove'

>>> a_tuple.index('exemple')            (3)
4
>>> 'z' in a_tuple                (4)
True

(1) Vous ne pouvez pas ajouter des éléments à un tuple. Un tuple n’a pas de méthode append() ou extend().

(2) Vous ne pouvez pas supprimer d’éléments dans un tuple, Les tuples n’ont pas de méthode remove() ou pop().

(3) Vous pouvez rechercher un élément dans un tuple, car ça ne modifie pas le tuple.

(4) Vous pouvez aussi utiliser l’opérateur in pour vérifier qu’un élément est présent dans le tuple.

Alors à quoi peuvent bien servir les tuples ?

  • Les tuples sont plus rapides que les listes. Quand vous définissez un ensemble constant de valeurs et que tout ce à quoi vous allez vous en servir est de le consulter, utilisez un tuple.
  • Cela rend votre code plus sûr de « protéger en écriture » des données qui ne sont pas appelées à être modifiées. Utiliser un tuple au lieu d’une liste, c’est comme disposer d’une instruction assert implicite qui montre que ces données sont des constantes, et qu’un effort de réflexion supplémentaire (et une fonction spécifique) est nécessaire pour contourner cela.
  • Certains tuples peuvent être utilisés comme clés dans un dictionnaire (en particulier des tuples qui contiennent des valeurs immuables, comme des chaînes, des nombres et d’autres tuples). Les listes ne doivent jamais être utilisées comme des clés de dictionnaire, parce que les listes ne sont pas immuables.
  • Les tuples peuvent être convertis en listes, et inversement. La fonction intégrée tuple() prend une liste en argument et en fait un tuple contenant les mêmes éléments, et la fonction list() prend un tuple en argument et en fait une liste. En fait, tuple() gèle la liste, et list() dégèle le tuple.

III-E-1. Les tuples dans un contexte booléen

Vous pouvez utiliser les tuples dans un contexte booléen tel qu’une instruction if.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
>>> def est_ce_vrai(quelque_chose):
    if quelque_chose:
        print("oui, c'est vrai")
    else:
        print("non, c'est faux")

        
>>> est_ce_vrai(())            (1)
non, c'est faux
>>> est_ce_vrai(('a','b'))        (2)
oui, c'est vrai
>>> est_ce_vrai((False,))        (3)
oui, c'est vrai
>>> type((False))                (4)
<class 'bool'>
>>> type((False,))
<class 'tuple'>

(1) Dans un contexte booléen, un tuple vide est faux.

(2) Tout tuple contenant au moins un élément est vrai.

(3) Tout tuple contenant au moins un élément est vrai. La valeur des éléments est sans importance. Mais que fait là cette virgule ?

(4) Pour créer un tuple avec un seul élément, il faut ajouter une virgule après cet élément. Sans cette virgule, Python estime que vous avez ajouté une paire de parenthèses supplémentaire inutile, mais ça ne crée pas un tuple.

III-E-2. Affecter de multiples valeurs à la fois

Voici un raccourci de programmation vraiment super : en Python vous pouvez utiliser un tuple pour affecter de multiples valeurs d’un coup.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
>>> v=('a',2,True)
>>> (x,y,z) = v        (1)
>>> x
'a'
>>> y
2
>>> z
True

(1) v est un tuple de trois valeurs et (x,y,z) est un tuple de trois variables. Affecter l’un à l’autre revient à affecter à chaque variable du premier la valeur correspondante du second.

Cela sert à toutes sortes de choses. Supposons que vous vouliez affecter des noms à une série de valeurs. Vous pouvez utiliser la fonction interne range() avec affectation multiple de variables pour affecter rapidement des valeurs consécutives.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
>>> (LUNDI,MARDI,MERCREDI,JEUDI,VENDREDI,SAMEDI,DIMANCHE)=range(7)    (1)
>>> LUNDI                                            (2)
0
>>> MARDI
1
>>> DIMANCHE
6

(1) La fonction interne range() construit une suite de nombres entiers. Techniquement parlant, la fonction range() retourne un itérateur, et non une liste ou un tuple, mais vous en apprendrez plus sur cette distinction plus tard. LUNDI, MARDI, MERCREDI, JEUDI, VENDREDI, SAMEDI et DIMANCHE sont les variables que vous définissez. (Cet exemple provient du module calendar, un petit module amusant qui imprime des calendriers, comme le programme UNIX cal. Le module calendar définit des constantes entières pour les jours de la semaine.)

(2) Maintenant chaque variable contient sa valeur : LUNDI vaut 0, MARDI vaut 1, etc.

Vous pouvez aussi utiliser l’affectation multiple de variables pour construire des fonctions qui retournent des valeurs multiples, simplement en retournant un tuple contenant toutes les valeurs. Le programme appelant peut traiter le résultat comme un unique tuple ou affecter les valeurs à une série de variables. Beaucoup de bibliothèques standard de Python font cela, y compris le module os dont vous ferez la connaissance dans le prochain chapitre.

III-F. Les ensembles (ou Sets)

Un ensemble, ou set, est un fourre-tout non ordonné de valeurs uniques. Un même ensemble peut contenir des valeurs de n’importe quel type immuable de données. Dès que vous avez deux ensembles, vous pouvez effectuer des opérations standard comme l’union, l’intersection ou la différence d’ensembles.

III-F-1. Créer un ensemble

Commençons par le commencement. Créer un ensemble est facile.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
>>> a_set={1}    (1)
>>> a_set
{1}
>>> type(a_set)    (2)
<class 'set'>
>>> a_set={1,2}
>>> a_set        (3)
{1, 2}

(1) Pour créer un ensemble (appelé set en Python) contenant une seule valeur, mettez cette valeur entre accolades.

(2) Les ensembles sont en fait implémentés en tant que classes, mais ne vous en souciez pas pour le moment.

(3) Pour créer un ensemble de plusieurs valeurs, séparez-les par des virgules et englobez le tout dans des accolades.

Vous pouvez aussi créer un ensemble à partir d’une liste.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
>>> a_list=['a','b','mpilgrim',True,False,42]
>>> a_set=set(a_list)            (1)
>>> a_set                    (2)
{False, True, 'a', 42, 'b', 'mpilgrim'}
>>> a_list                    (3)
['a', 'b', 'mpilgrim', True, False, 42]

(1) Pour créer un ensemble à partir d’une liste, utilisez la fonction set(). (Les conformistes qui savent comment les ensembles sont implémentés diront qu’il ne s’agit pas ici de l’appel d’une fonction, mais plutôt de l’instanciation d’une classe. Je promets que vous apprendrez la différence plus loin dans ce livre. Pour le moment, contentez-vous de retenir que set() agit comme une fonction et retourne un ensemble.)

(2) Comme je l’ai signalé plus haut, un ensemble peut contenir des valeurs de n’importe quel type. Et comme je l’ai signalé plus haut encore, les ensembles ne sont pas ordonnés. Cet ensemble ne se souvient pas de l’ordre initial des éléments de la liste qui a servi à le créer. Si vous ajoutiez des éléments à cet ensemble, il ne se souviendrait pas de l’ordre dans lequel vous les avez ajoutés.

(3) La liste originale reste inchangée.

Vous n’avez encore aucune valeur à ajouter ? Pas de problème : vous pouvez créer un ensemble vide.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
>>> a_set=set()        (1)
>>> a_set            (2)
set()
>>> type(a_set)        (3)
<class 'set'>
>>> len(a_set)        (4)
0
>>> not_sure={}        (5)
>>> type(not_sure)
<class 'dict'>

(1) Pour créer un ensemble vide, appelez la fonction set() sans argument.

(2) La représentation affichée d’un ensemble vide a l’air un peu bizarre. Vous attendiez-vous à {} peut-être ? Cela désignerait un dictionnaire vide, non un ensemble vide. Vous en apprendrez plus sur les dictionnaires un peu plus loin dans ce chapitre.

(3) Malgré la représentation bizarre, ceci est bien un ensemble…

(4) …et cet ensemble n’a pas d’éléments.

(5) À cause de bizarreries historiques héritées de Python 2, vous ne pouvez pas créer un ensemble vide avec deux accolades. Cela crée un dictionnaire vide, et non un ensemble vide.

III-F-2. Modifier un ensemble

Il y a deux manières différentes d’ajouter un élément à un ensemble, la méthode add() et la méthode update().

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
>>> a_set={1,2}
>>> a_set.add(4)        (1)
>>> a_set
{1, 2, 4}
>>> len(a_set)        (2)
3
>>> a_set.add(1)        (3)
>>> a_set
{1, 2, 4}
>>> len(a_set)        (4)
3

(1) La méthode add() prend un unique argument, qui peut être de n’importe quel type, et ajoute la valeur à l’ensemble.

(2) Cet ensemble contient maintenant trois éléments.

(3) Les ensembles sont des sacs contenant des valeurs uniques. Si vous essayez d’ajouter une valeur qui existe déjà dans l’ensemble, rien ne se passe. Cela ne lèvera pas d’exception, c’est juste une non-opération.

  1. L’ensemble contient toujours trois éléments.
 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
>>> a_set={1,2,3}
>>> a_set
{1, 2, 3}
>>> a_set.update({2,4,6})            (1)
>>> a_set                        (2)
{1, 2, 3, 4, 6}
>>> a_set.update({3,6,9},{1,2,3,5,8,13})    (3)
>>> a_set
{1, 2, 3, 4, 5, 6, 8, 9, 13}
>>> a_set.update([10,20,30])            (4)
>>> a_set
{1, 2, 3, 4, 5, 6, 8, 9, 10, 13, 20, 30}

(1) La méthode update() prend comme argument un ensemble et ajoute tous ses éléments à l’ensemble initial. C’est comme si vous appeliez la méthode add() pour chacun des éléments.

(2) Les doublons sont ignorés, parce qu’un ensemble ne peut pas contenir de doublon.

(3) En réalité, vous pouvez appeler la méthode update() avec autant d’arguments que vous voulez. Si vous l’appelez avec deux ensembles, elle ajoutera tous les éléments des deux ensembles à l’ensemble original (en ignorant les doublons).

(4) La méthode update() accepte nombre de types de données différents, y compris les listes. Quand vous passez une liste en paramètre, la méthode update() ajoute tous les éléments de la liste à l’ensemble original (en ignorant les doublons, bien sûr).

III-F-3. Retirer des éléments d’un ensemble

Il y a trois manières de retirer un élément d’un ensemble. Les deux premières, discard() et remove() ont une subtile différence.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
>>> a_set={1,3,6,10,15,21,28,36,45}
>>> a_set
{1, 3, 36, 6, 10, 45, 15, 21, 28}
>>> a_set.discard(10)        (1)
>>> a_set
{1, 3, 36, 6, 45, 15, 21, 28}
>>> a_set.discard(10)        (2)
>>> a_set
{1, 3, 36, 6, 45, 15, 21, 28}
>>> a_set.remove(21)        (3)
>>> a_set
{1, 3, 36, 6, 45, 15, 28}
>>> a_set.remove(21)        (4)
Traceback (most recent call last):
  File "<pyshell#24>", line 1, in <module>
    a_set.remove(21)
KeyError: 21

(1) La méthode discard() prend un élément unique en argument et retire cette valeur de l’ensemble.

(2) Si vous appelez la méthode discard() avec une valeur qui n’existe pas, il ne se passe rien. C’est une non-opération.

(3) La méthode remove() prend également un élément unique en argument et retire également cette valeur de l’ensemble.

(4) Et voilà la différence : si la valeur n’existe pas dans l’ensemble, la méthode remove() lève une exception KeyError.

Comme les listes, les ensembles possèdent une méthode pop().

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
>>> a_set={1,3,6,10,15,21,28,36,45}
>>> a_set.pop()            (1)
1
>>> a_set.pop()
3
>>> a_set.pop()
36
>>> a_set
{6, 10, 45, 15, 21, 28}
>>> a_set.clear()            (2)
>>> a_set
set()
>>> a_set.pop()            (3)
Traceback (most recent call last):
  File "<pyshell#32>", line 1, in <module>
    a_set.pop()
KeyError: 'pop from an empty set'

(1) La méthode pop() retire une seule valeur de l’ensemble et retourne cette valeur. Cependant, comme les ensembles sont non-ordonnés, il n’y a pas de « dernière » valeur dans un ensemble, aussi est-il impossible de contrôler quelle valeur sera retirée. C’est totalement aléatoire.

(2) La méthode clear() supprime tous les éléments de l’ensemble et laisse un ensemble vide. C’est équivalent à a_set = set() qui créerait un ensemble vide et écraserait la variable a_set avec cet ensemble vide.

(3) Tenter de supprimer une valeur dans un ensemble vide avec la méthode pop() provoque une exception KeyError.

III-F-4. Opérations courantes sur les ensembles

Le type set de Python supporte plusieurs opérations courantes sur les ensembles.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
>>> a_set={2,4,5,9,12,21,30,51,76,127,195}
>>> 30 in a_set                        (1)
True
>>> 31 in a_set
False
>>> b_set={1,2,3,5,6,8,9,12,15,17,18,21}
>>> a_set.union(b_set)                    (2)
{1, 2, 195, 4, 5, 3, 6, 8, 9, 76, 12, 15, 17, 18, 21, 30, 51, 127}
>>> a_set.intersection(b_set)                  (3)
{9, 2, 21, 12, 5}
>>> a_set.difference(b_set)                (4)
{195, 4, 76, 51, 30, 127}
>>> a_set.symmetric_difference(b_set)        (5)
{1, 3, 195, 6, 4, 8, 76, 15, 17, 18, 51, 30, 127}

(1) Pour tester si une valeur appartient à un ensemble, utilisez l’opérateur in. Ça fonctionne comme pour les listes.

(2) La méthode union() retourne un nouvel ensemble contenant tous les éléments figurant dans l’un OU l’autre ensemble.

(3) La méthode insertection() retourne un nouvel ensemble contenant tous les éléments figurant dans l’un ET l’autre ensemble.

(4) La méthode difference() retourne un nouvel ensemble contenant tous les éléments qui sont dans a_set mais pas dans b_set.

(5) La méthode symmetric_difference() retourne un nouvel ensemble contenant tous les éléments se trouvant exclusivement dans l’un des deux ensembles.

Trois de ces méthodes sont symétriques.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
# suite de l'exemple précédent
>>> b_set.symmetric_difference(a_set)                        (1)
{1, 195, 4, 3, 6, 8, 76, 15, 17, 18, 51, 30, 127}
>>> b_set.symmetric_difference(a_set)==a_set.symmetric_difference(b_set)
True                                                (2)
>>> b_set.union(a_set)==a_set.union(b_set)                    (3)
True
>>> b_set.intersection(a_set)==a_set.intersection(b_set)            (4)
True
>>> b_set.difference(a_set)==a_set.difference(b_set)                (5)
False

(1) La différence symétrique entre a_set et b_set a l’air différente de la différence symétrique entre b_set et a_set, mais souvenez-vous, les ensembles sont non ordonnés. Deux ensembles contenant toutes les mêmes valeurs (sans aucune valeur restante) sont considérés comme égaux.

(2) Et c’est exactement ce qui se passe ici. Ne vous laissez pas induire en erreur par leur représentation écrite dans le shell Python. Ils contiennent les mêmes valeurs, donc ils sont égaux.

(3) L’union de deux ensembles est également symétrique.

(4) L’intersection de deux ensembles est également symétrique.

(5) La différence de deux ensembles n’est pas symétrique. Ça paraît logique, c’est comme soustraire un nombre d’un autre. L’ordre des opérandes compte.

Enfin, il y a quelques questions que vous pouvez vous poser sur les ensembles.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
>>> a_set={1,2,3}
>>> b_set={1,2,3,4}
>>> a_set.issubset(b_set)    (1)
True
>>> b_set.issuperset(a_set)    (2)
True
>>> a_set.add(5)            (3)
>>> a_set.issubset(b_set)
False
>>> b_set.issuperset(a_set)
False

(1) a_set est un sous-ensemble de b_set. Tous les membres de a_set sont aussi membres de b_set.

(2) En posant la question à l’envers, b_set est un surensemble de a_set, tous les membres de a_set sont aussi membres de b_set.

(3) Dès que vous ajoutez une valeur dans a_set, qui n’est pas dans b_set, les deux tests retournent False.

III-F-5. Les ensembles dans un contexte booléen

Vous pouvez utiliser les ensembles dans un contexte booléen comme une instruction if.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
>>> def est_ce_vrai(quelque_chose):
    if quelque_chose:
        print("oui, c'est vrai")
    else:
        print("non, c'est faux")

        
>>> est_ce_vrai(set())        (1)
non, c'est faux
>>> est_ce_vrai({'a'})        (2)
oui, c'est vrai
>>> est_ce_vrai({False})    (3)
oui, c'est vrai

(1) Dans un contexte booléen, un ensemble vide est faux.

(2) N’importe quel ensemble avec au moins un élément est vrai.

(3) N’importe quel ensemble avec au moins un élément est vrai. La valeur de l’élément est sans importance.

III-G. Les dictionnaires (dictionaries)

Un dictionnaire est un ensemble non ordonné de paires clé-valeur. Quand vous ajoutez une clé à un dictionnaire, il vous faut aussi ajouter une valeur pour cette clé. (Vous pouvez toujours changer cette valeur plus tard). Les dictionnaires Python sont optimisés pour obtenir la valeur quand vous connaissez la clé, mais pas dans l’autre sens.

Un dictionnaire en Python, c’est comme un hash en Perl 5. En Perl 5, les variables contenant un hash commencent toujours par le caractère %. En Python, les variables peuvent être nommées n’importe comment, c’est Python qui en mémorise le type en interne.

III-G-1. Créer un dictionnaire

Créer un dictionnaire est facile. La syntaxe est similaire à celle des ensembles, mais au lieu de valeurs, il contient des paires clé-valeur. Dans votre dictionnaire, vous pourrez accéder à une valeur par sa clé.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
>>> a_dict={'server':'db.diveintopython3.org','database':'mysql'}    (1)
>>> a_dict
{'server': 'db.diveintopython3.org', 'database': 'mysql'}
>>> a_dict['server']                                    (2)
'db.diveintopython3.org'
>>> a_dict['database']                                      (3)
'mysql'
>>> a_dict['db.diveintopython3.org']                          (4)
Traceback (most recent call last):
  File "<pyshell#7>", line 1, in <module>
    a_dict['db.diveintopython3.org']
KeyError: 'db.diveintopython3.org'

(1) Pour commencer, vous créez un dictionnaire contenant deux éléments et vous l’affectez à la variable a_dict. Chaque élément est une paire clé-valeur et l’ensemble des éléments est compris entre accolades.

(2) 'server' est une clé, et sa valeur associée, référencée par a_dict['server'], est 'db.diveintopython3.org'.

(3) 'database' est une clé, et sa valeur associée, référencée par a_dict['database'], est 'mysql'.

(4) Vous pouvez accéder aux valeurs par leurs clés, mais vous ne pouvez pas accéder à une clé par sa valeur. Ainsi a_dict['server'] renvoie 'db.diveintopython3.org', mais a_dict['db.diveintopython3.org'] lève une exception, parce que 'db.diveintopython3.org' n’est pas une clé.

III-G-2. Modifier un dictionnaire

Les dictionnaires n’ont pas de taille limite prédéfinie. Vous pouvez ajouter de nouvelles paires clé-valeur à tout moment, ou vous pouvez modifier la valeur d’une clé existante.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
>>> # suite de l'exemple précédent
>>> a_dict
{'database': 'mysql', 'server': 'db.diveintopython3.org'}
>>> a_dict['database']='blog'                  (1)
>>> a_dict        
{'database': 'blog', 'server': 'db.diveintopython3.org'}
>>> a_dict['user']='mark'                (2)
>>> a_dict                            (3)
{'database': 'blog', 'user': 'mark', 'server': 'db.diveintopython3.org'}
>>> a_dict['user']='dora'                (4)
>>> a_dict
{'database': 'blog', 'user': 'dora', 'server': 'db.diveintopython3.org'}
>>> a_dict['User']='mark'                (5)
>>> a_dict
{'database': 'blog', 'user': 'dora', 'User': 'mark', 'server': 'db.diveintopython3.org'}

(1) Vous ne pouvez pas avoir de clés dupliquées dans un dictionnaire. Affecter une valeur à une clé existante écrase l’ancienne valeur.

(2) Vous pouvez ajouter des paires clé-valeur à tout moment. La syntaxe est identique à celle de la modification d’une valeur existante.

(3) Le nouvel élément de dictionnaire (clé 'user', valeur 'mark') est situé au milieu. En fait, que les valeurs apparaissent ordonnées dans le premier exemple est une coïncidence. Qu’elles apparaissent ici dans le désordre est tout aussi fortuit.

(4) Affecter une nouvelle valeur à une clé existante du dictionnaire revient à remplacer l’ancienne valeur de la clé par la nouvelle.

(5) Ceci va-t-il remettre la valeur de la clé 'user' à l’ancienne valeur 'mark' ? Non ! Regardez la clé de plus près : le 'U' de 'User' est en majuscule. Les clés de dictionnaire sont sensibles à la casse, ainsi cette instruction crée-t-elle une nouvelle paire clé-valeur au lieu d’écraser la paire existante. Elles peuvent vous paraître similaires, mais aux yeux de Python, il s’agit de deux choses totalement différentes.

III-G-3. Dictionnaires à valeurs mélangées

Les dictionnaires ne sont pas que pour les chaînes de caractères. Les valeurs d’un dictionnaire peuvent être de n’importe quel type, y compris les entiers, les booléens, des objets quelconques, ou même d’autres dictionnaires. Et dans un même dictionnaire, les valeurs n’ont pas à être du même type, vous pouvez le mélanger et les apparier à votre guise. Les clés de dictionnaires sont plus limitées, mais elles peuvent être des chaînes, des entiers et quelques autres types. Vous pouvez aussi mélanger et assortir les types des clés d’un dictionnaire.

En fait, vous avez déjà vu un dictionnaire avec des clés et des valeurs qui ne sont pas des chaînes de caractères, dans votre premier programme Python.

 
Sélectionnez
SUFFIXES = {1000: ['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'], 1024: ['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']}

Décortiquons cela dans le shell interactif.

 
Sélectionnez
>>> SUFFIXES={1000:['KB','MB','GB','TB','PB','EB','ZB','YB'],1024:['KiB','MiB','GiB','TiB','PiB','EiB','ZiB','YiB']}
>>> len(SUFFIXES)                    (1)
2
>>> 1000 in SUFFIXES                (2)
True
>>> SUFFIXES[1000]                (3)
['KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB']
>>> SUFFIXES[1024]                (4)
['KiB', 'MiB', 'GiB', 'TiB', 'PiB', 'EiB', 'ZiB', 'YiB']
>>> SUFFIXES[1000][3]                (5)
'TB'

(1) Comme pour les listesLes Listes et les ensemblesLes ensembles (ou Sets), la fonction len() vous donne le nombre d’éléments du dictionnaire.

(2) Et comme pour les listes et les ensembles, vous pouvez utiliser l’opérateur in pour vérifier si une clé est définie dans le dictionnaire.

(3) 1000 est une clé du dictionnaire SUFFIXES. Sa valeur est une liste de huit éléments (huit chaînes de caractères pour être précis).

(4) De même, 1024 est une clé du dictionnaire SUFFIXES. Sa valeur est également une liste de huit éléments.

(5) Comme SUFFIXES[1000] est une liste, vous pouvez adresser les éléments individuels de la liste par leur index à base zéro.

III-G-4. Dictionnaires dans un contexte booléen

Vous pouvez aussi utiliser un dictionnaire dans un contexte booléen, tel qu’une instruction if.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
>>> def est_ce_vrai(quelque_chose):
    if quelque_chose:
        print("oui, c'est vrai")
    else:
        print("non, c'est faux")

        
>>> est_ce_vrai({})        (1)
non, c'est faux
>>> est_ce_vrai({'a':1})    (2)
oui, c'est vrai

(1) Dans un contexte booléen, un dictionnaire vide est faux.

(2) Tout dictionnaire contenant au moins une paire clé-valeur est vrai.

III-H. None

None est une constante spéciale en Python. C’est une valeur nulle. None n’est pas la même chose que False. None n’est pas 0. None n’est pas une chaîne vide. Comparer None à n’importe quoi d’autre que None retournera toujours False.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
>>> type(None)
<class 'NoneType'>
>>> None==False
False
>>> None==0
False
>>> None==''
False
>>> None==None
True
>>> x=None
>>> x==None
True
>>> y=None
>>> x==y
True

III-H-1. None dans un contexte booléen

Dans un contexte booléen, None est faux et not None est vrai.

 
Sélectionnez
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
>>> def est_ce_vrai(quelque_chose):
    if quelque_chose:
        print("oui, c'est vrai")
    else:
        print("non, c'est faux")
        
>>> est_ce_vrai(None)
non, c'est faux
>>> est_ce_vrai(not None)
oui, c'est vrai

III-I. Pour aller plus loin


précédentsommaire

Vous avez aimé ce tutoriel ? Alors partagez-le en cliquant sur les boutons suivants : Viadeo Twitter Facebook Share on Google+   

  

Les sources présentées sur cette page sont libres de droits et vous pouvez les utiliser à votre convenance. Par contre, la page de présentation constitue une œuvre intellectuelle protégée par les droits d'auteur. Copyright © 2019 Mark Pilgrim. Aucune reproduction, même partielle, ne peut être faite de ce site ni de l'ensemble de son contenu : textes, documents, images, etc. sans l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.