Chapire 1 - Partie 5
Cette partie est consacrée aux dictionnaires (dict)
1. Les collections non ordonnées¶
-
- 1.1. Le dictionnaire
- 1.1.1. Création
- 1.1.2. Opérateur d'indexation
- 1.1.3. Exemple pour TP
- 1.1.4. Opérations sur les dictionnaires
- 1.1.4.1. Mise à jour
- 1.1.4.2. Fusion de dictionnaires
- 1.1.5. Fonctions d'accès
- 1.1.6. autres fonctions
- 1.1. Le dictionnaire
1.1. Le dictionnaire¶
Un dictionnaire en python (dict) est un type de variable qui sert à stocker des informations sous forme de paires : une clé et une valeur. Chaque clé permet de retrouver rapidement la valeur qui lui correspond.
Le dictionnaire python entre dans la catégorie des types de données dits de collection non ordonnée, contrairement aux collections séquentielles (str, list et tuple) qui sont ordonnées indexées par numéros de positions (chaque élément a une position, un indice). Un dictionnaire est indexé par des clés uniques.
On accède aux éléments d'un dictionnaire à l'aide d'une clé au lieu d'un indice
Le dictionnaire est aussi ce qu'on appelle un contenant associatif, car il associe une valeur à une clé d'accès
Les clés d'un dictionnaire doivent être immuables (comme les str, int, flot, tuple) tandis que les valeurs peuvent être de n’importe quel type d’objet y compris un autre dictionnaire
Les clés aussi bien que les valeurs d'un dictionnaire peuvent être hétérogènes
On peut modifier les éléments du dictionnaire, tout comme on peut modifier les éléments d'une liste.
La paire
clé : valeurest aussi appelée une entrée du dictionnaire
1.1.1. Création¶
Pour créer un dictionnaire python, donc une variable de type dict, on dispose de 3 manières :
- La plus commune consiste à utiliser une paire d'accolades
{}entre lesquelles on insère des élémentsclé : valeurséparés par des virgules.d = {clé1: valeur1, clé2: valeur2, ...}
Si on ne met rien entres les deux accolades, le dictionnaire sera vide.
Utilisation de la fonction
fromkeys:d = dict.fromkeys(liste_cles,valeur_commune)
Utilisation du type
dictcomme fonction avec une paire de parenthèses :d = dict(entrées)
Les entrées peuvent être sous forme d'une série d'affectations ou une liste de tuples :
d = dict( clé1 = val1, clé2 = val2, ...)d = dict([('clé1, val1), (clé2, val2), ...])
Remarques
La liste de tuples peut être générée avec zip (voir les tuples), on écrit :
d = dict(zip(['clé1', 'clé2', ... ], [val1, val2, ... ]))Il est possible mélanger entre accolades et affectations, et entre liste de tuples et affectations
d = dict({clé1: val1, clé2: val2}, clé3 = val3, ...)d = dict([(clé1, val1), (clé2: val2)], clé3 = val3, ...)
Voici quelques exemples d'illustration:
# Création de dictionnaires vide avec les 3 méthodes
d1 = {}
d2 = dict.fromkeys([])
d3 = dict('') # on peut mettre entre les parenthèses
# tout itérable vide : ([]), ({}), ( () ), ('')
print(' dictionnaires vides :')
print(f"{d1 = }")
print(f"{d2 = }")
print(f"{d3 = }")
dictionnaires vides :
d1 = {}
d2 = {}
d3 = {}
# Création de dictionnaires à 3 entrées
d4 = dict({'a': 1, 'b': 2, 'c' : 3}) # accolades
d5 = dict( a = 1, b = 2, c = 3 ) # affectation
d6 = dict([('a', 1), ('b', 2), ('c' , 3)]) # liste de tuples
d7 = dict({ 'a': 1 , 'b': 2}, c = 3) # mélange accolade + affectation
d8 = dict([('a', 1), ('b', 2)], c = 3) # liste de tuples + affectation
l = list(zip(['a','b', 'c' ],[1, 2, 3 ])) # liste de tuples générés avec zip
d9 = dict(l)
print(f'liste de tuples {l = }')
print('tous les dict sont les mêmes ? :', d4 == d5 == d6 == d7 == d8 == d9)
liste de tuples l = [('a', 1), ('b', 2), ('c', 3)]
tous les dict sont les mêmes ? : True
# un autre exemple : dictionnaire de 3 entrées pour la conversion d'unités SI
# utilisation d'accolades
unit_SI = {'cm' : 0.01, # cm = 0.01 m
'g' : 0.001, # g = 0.001 kg
'min': 60 # min = 60 s
}
print("Conversion d'unités en SI :", unit_SI)
Conversion d'unités en SI : {'cm': 0.01, 'g': 0.001, 'min': 60}
- Les éléments du dictionnaire sont insérés en les séparant par des virgules
- Chaque élément est constitué d'une clé d'accès unique et d'une valeur séparées par deux point
:
La méthode fromkeys de dict permet de créer un dictionnaire en initialisant, en même temps, un ensemble de clés à une valeur commune.
dictionnaire = dict.fromkeys(liste_cles,valeur_commune)
L'ensemble des clés liste_cles doit être un itérable (comme str, list, tuple, ...)
Si valeur_commune n'est pas donnée, toutes les clés vont être initialisées par défaut à None
Voici quelques exemples:
d1 = dict.fromkeys('abc') # 3 entrées avec un str non définies
print(f'{d1 = }')
d2 = dict.fromkeys(('a', 'b','c')) # 4 entrées avec un tuple non définies
print(f'{d2 = }')
sub_units = dict.fromkeys(['mm', 'g', 'ms'], 0.001) # 3 entrées toutes les clés =0.001
print(f'{sub_units = }')
d1 = {'a': None, 'b': None, 'c': None}
d2 = {'a': None, 'b': None, 'c': None}
sub_units = {'mm': 0.001, 'g': 0.001, 'ms': 0.001}
1.1.2. Opérateur d'indexation¶
De la même manière que pour les listes et les tuples, on accède à un élément d'un dictionnaire en utilisant une paire de crochets [] comme opérateur. Il prend une clé d'accès en argument.
# Exemple d'utilisation du dictionnaire unit_SI
# On se donne une valeur d'une masse en grammes et on la convertie en kg avant de l'afficher
M = 1500 * unit_SI['g'] # [1500 g -> 1.5 kg]
L = 350 * unit_SI['cm'] # [250 cm -> 3.5 m]
t = 5 * unit_SI['min'] # [5 min -> 300 s]
print(f'Masse {M = } kg') # affichage en SI
print(f'Longueur {L = } m ')
print(f'Temps {t = } s ')
Masse M = 1.5 kg Longueur L = 3.5 m Temps t = 300 s
Dans cette exemple unit_SI["min"] va retourner la valeur 60 qui sera multiplié par 5 avant d'être affecté à la variable t qui devient : 5*60=300 secondes.
Si on tente d'accéder à une clé qui n'existe pas dans le dictionnaire, cela va provoquer une erreur de type KeyError.
Par exemple :
>>> print(unit_SI['km'])
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
KeyError: 'km'
>>>
La clè 'km' n'existe pas dans le dictionnaire unit_SI.
L'opérateur double crochets [] permet aussi d'ajouter une entrée à un dictionnaire comme suit :
dictionnaire[cle] = valeur.
La conversion de km en m peut donc être ajoutée au dictionnaire unit_SI avec le code suivant :
unit_SI['km'] = 1000.0
print(f"{unit_SI = }")
unit_SI = {'cm': 0.01, 'g': 0.001, 'min': 60, 'km': 1000.0}
A noter que la clè km et la valeur 1000.0 ont été ajoutées comme une nouvelle entrée en fin du dictionnaire unit_SI.
L'opérateur paire de crochets [] permet aussi de modifier la valeur d'une clé si celle-ci existe dans le dictionnaire.
Exemple : supposant qu'on initialise des multiples d'unités : kilomètre, tonne et heure à 1000, puis on rectifie l'heure en 3600 s
mul_units = dict.fromkeys(['km', 't', 'h'], 1000) # 3 entrées toutes les clés =0.001
print(f'{mul_units = }')
mul_units['h'] = 3600 # modification de la clé 'h'
print(f'{mul_units = }')
mul_units = {'km': 1000, 't': 1000, 'h': 1000}
mul_units = {'km': 1000, 't': 1000, 'h': 3600}
1.1.3. Exemple pour TP¶
Voici un exemple de dictionnaire de propriétés qui regroupe à la fois:
- deux entrées clé:valeur simples : 'g' et 'T' qui peuvent être des paramètres globaux d'un problème de MDF
- deux autres entrées complexes dont les valeurs sont des dictionnaires : 'eau' et 'air' qui regroupent leurs propriétés.
- On peut le completer en y ajoutant d'autres propriétés ou d'autres fluides.
- On cherche à prendre en compte les unités des propriétés
- Définir des propriétés dépendantes de la température
# Dictionnaires des propriétés (props) contenant :
# g et T comme paramètres globaux
# propriétés de l'eau sous forme d'un 1er dictionnaire
# propriétés de l'air sous forme d'un 2nd dictionnaire
props = {
'g' : 9.80665, # gravité (m/s^2)
'T' : 20.0, # température (°C)
'eau' : {
'rho' : 998.2, # densité de l'eau (kg/m^3)
'mu' : 1.0016e-3, # viscosité dynamique (Pa·s)
'sigma': 0.0728 # tension superficielle (N/m)
},
'air' : {
"rho" : 1.225, # densité de l'air (kg/m³)
"mu" : 1.8e-5 # viscosité dynamique (Pa·s)
}
}
# affichage des propriétés de l'eau
print(f"propriétés de l'eau : {props['eau']}")
# affichage de rho de l'eau
print(f"densité de l'eau : {props['eau']['rho']} (kg/m^3)")
# si veut calculer la viscosité cinématique de l'eau
nu = props['eau']['mu']/props["eau"]["rho"]
print(f"viscosité cinématique de l'eau : {nu = :.4e}")
propriétés de l'eau : {'rho': 998.2, 'mu': 0.0010016, 'sigma': 0.0728}
densité de l'eau : 998.2 (kg/m^3)
viscosité cinématique de l'eau : nu = 1.0034e-06
Dans l'exemple précédent, on a accédé à la valeur de la densité de l'eau par utilisation d'une double paire de crochets.
Exemple props["eau"]["rho"].
La 1ere paire de crochets :props['eau'] permettent d'extraire toutes les propriétés qui sont définies dans le dictionnaire eau. L'affichage donne :
{'rho': 998.2, 'mu': 0.0010016, 'sigma': 0.0728}
La seconde paire de crochets permettent d'extraire une propriété en particulier comme 'rho'
1.1.4. Opérations sur les dictionnaires¶
Nous avons vu les trois fonctions de l'opérateur crochets [] qui permet l'ajout, l'extraction et la modification d'une entrée d'un dictionnaires.
Nous avons aussi vue la fonctions fromkeys qui permet de créer et d'initialiser un dictionnaire.
En plus à cela, il existe 10 autres fonctions qui permettent de réaliser des opérations sur les dictionnaires python. Elles peuvent être regroupées comme suit :
- 2 fonctions d'ajout et de mise à jour :
updateetsetdefault - 3 fonctions de suppression :
pop,popitemetclear - 4 fonction d'accès aux composantes :
get,items,keysetvalues - la 10ème sert à réaliser une copie intégrale d'un dictionnaire :
copy
Les objets renvoyés par dict.keys(), dict.values() et dict.items() sont des vues. Ils fournissent une vue dynamique des éléments du dictionnaire, ce qui signifie que si le dictionnaire change, la vue reflète ces changements.
Les vues de dictionnaires peuvent être itérées et ainsi renvoyer les données du dictionnaire ; elles gèrent aussi les tests d'appartenance :
len(dictview)
Renvoie le nombre d'entrées du dictionnaire.
iter(dictview)
Renvoie un itérateur sur les clés, les valeurs ou les éléments (représentés par des paires (clé, valeur)) du dictionnaire.
1.1.4.1. Mise à jour¶
La méthode update
La méthode dict.update() met à jour un dictionnaire en ajoutant ou modifiant plusieurs paires clé-valeur à partir d’un autre dictionnaire, d’un itérable de paires, ou d’arguments nommés.
- Elle remplace les valeurs des clés existantes
- Ajoute les nouvelles clés
- Modifie le dictionnaire en place.
- Ne retourne aucune valeur, le résultat de verra dans le dictionnaire lui même.
Sa syntaxe est : d1.update(d2)
Le dictionnaire d1sera mis à jour avec la dictionnaire d2. Si une clé existe dans les deux dictionnaires, la valeur du second dictionnaire prévaut.
Le dictionnaire d2peut être une variable dict déjà définie ou une des expression de créations de dictionnaire que nous avons présenté en 1.1.1
La fonction update ne retourne rien, le résultat de verra dans le dictionnaire d1.
La méthode setdefault
Ma méthode dict.setdefault() accède à la valeur d’une clé ; si elle n’existe pas, insère la clé avec une valeur par défaut et retourne cette valeur.
Sa syntaxe : dict.setdefault(clé, valeur_par_défaut = None)
- Elle ne modifie pas les valeurs des clés existantes contrairement à update
- Ajoute la clé seulement si elle est absente
- Retourne la valeur de la clé (existante ou par défaut).
Différences entre les deux fonctions
- Portée : update() gère plusieurs clés ; setdefault() gère une seule clé.
- Clés existantes : update() remplace les valeurs ; setdefault() les conserve.
- Retour : update() retourne None ; setdefault() retourne la valeur de la clé.
- Usage : update() pour fusionner/modifier en masse ; setdefault() pour initialiser une clé si absente.
props_eau = {"rho" : 998.204, "mu" : 1.00e-3} # densité et viscosité
print('Ajout de sigma et n :')
props_eau.update({'sigma': 0.0738, 'n': 1.33}) # Ajout avec un dictionnaire {}
print(f"{props_eau = }")
print('\nupdate rho :')
props_eau.update({'rho': 1030}) # Modification de rho
print(f"{props_eau = }")
print('\nun autre update de rho :')
props_eau.update(rho = 1025) # Une autre modification de rho (sans ' ')
print(f"{props_eau = }")
Ajout de sigma et n :
props_eau = {'rho': 998.204, 'mu': 0.001, 'sigma': 0.0738, 'n': 1.33}
update rho :
props_eau = {'rho': 1030, 'mu': 0.001, 'sigma': 0.0738, 'n': 1.33}
un autre update de rho :
props_eau = {'rho': 1025, 'mu': 0.001, 'sigma': 0.0738, 'n': 1.33}
Utilisation de la fonction setdefault
ct = props_eau.setdefault('ct',0.5715) # ajout d'une propriété avec setdefault (ct : conductivité thermique)
print(f"{props_eau = }")
print(f"Conductivité thermique de l'eau : {ct = } W/m.K")
print('')
ct = props_eau.setdefault('ct',None) # 2nd appel à setdefault ne modifie ni props_eau ni ct
print("Après le deuxième appel de setdefault:")
print(f"{props_eau = }")
print(f"Conductivité thermique de l'eau : {ct = } W/m.K")
props_eau = {'rho': 1025, 'mu': 0.001, 'sigma': 0.0738, 'n': 1.33, 'ct': 0.5715}
Conductivité thermique de l'eau : ct = 0.5715 W/m.K
Après le deuxième appel de setdefault:
props_eau = {'rho': 1025, 'mu': 0.001, 'sigma': 0.0738, 'n': 1.33, 'ct': 0.5715}
Conductivité thermique de l'eau : ct = 0.5715 W/m.K
1.1.4.2. Fusion de dictionnaires¶
Nous avons vu comment la fonction update s'utilise pour mettre à jour un dictionnaire en lui ajoutant un autre.
Cette opération permet de fusionner les deux dictionnaire mais en perdant la copie initiale de celui sur lequel la fonction agit.
Afin de fusionner deux dictionnaires tout en gardant les deux versions initiales, on utilise l'opérateur | (ou)
d3 = d1 | d2
d1 = dict.fromkeys(['mm', 'g'], 0.001) # Fusion de deux dictionnaires
d2 = dict.fromkeys(['km', 't'], 1000)
d3 = dict.fromkeys(['cm', 'dag'], 0.01)
d3 = d1 | d2 | d3
print(f'{d1 = } \n{d2 = } \n{d3 = }')
d1 |= d2 # mise à jour de d1
d1 = {'mm': 0.001, 'g': 0.001}
d2 = {'km': 1000, 't': 1000}
d3 = {'mm': 0.001, 'g': 0.001, 'km': 1000, 't': 1000, 'cm': 0.01, 'dag': 0.01}
Si on veut absolument utiliser la fonction updatepour fusionner deux dictionnaires, il faut d'abord faire une copie de l'un d'eux, pour ensuite appliquer l'update sur la copie.
d1 = dict.fromkeys(['mm', 'g'], 0.001) # même exemple précédent
d2 = dict.fromkeys(['km', 't','h'], 1000)
d3 = d1.copy() # copie et fusion
d3.update(d2)
d3['h'] = 3600 # mise à jour de 'h' et affichage
print(f'{d1 = } \n{d2 = } \n{d3 = }')
d1 = {'mm': 0.001, 'g': 0.001}
d2 = {'km': 1000, 't': 1000, 'h': 1000}
d3 = {'mm': 0.001, 'g': 0.001, 'km': 1000, 't': 1000, 'h': 3600}
Remarque :
Attention toute de même à la fonction copy, si une des clé fait référence à une valeur mutable alors les modifications dans cette valeur se propagent entre le dictionnaire et sa copie.
# Exemple avec valeurs mutables
d1 = {'u' : [0.61, 0.82], 'p': 5 }
d2 = {'v' : [0.45, 0.89], 'q': 3 }
d3 = d1.copy() # copie et update
d3.update(d2)
print(f'{d1 = } \n{d2 = } \n{d3 = }')
d3['u'][0] = 0.65 # La modification de la liste dans d3 se propage à d1
print(f'\nModification de u[0] dans d3:\n{d1 = } \n{d2 = } \n{d3 = }')
d1['u'][1] = 0.87 # La modification la liste dans d1 se propage à d3
print(f'\nModification de u[1] dans d1 :\n{d1 = } \n{d2 = } \n{d3 = }')
d1 = {'u': [0.61, 0.82], 'p': 5}
d2 = {'v': [0.45, 0.89], 'q': 3}
d3 = {'u': [0.61, 0.82], 'p': 5, 'v': [0.45, 0.89], 'q': 3}
Modification de u[0] dans d3:
d1 = {'u': [0.65, 0.82], 'p': 5}
d2 = {'v': [0.45, 0.89], 'q': 3}
d3 = {'u': [0.65, 0.82], 'p': 5, 'v': [0.45, 0.89], 'q': 3}
Modification de u[1] dans d1 :
d1 = {'u': [0.65, 0.87], 'p': 5}
d2 = {'v': [0.45, 0.89], 'q': 3}
d3 = {'u': [0.65, 0.87], 'p': 5, 'v': [0.45, 0.89], 'q': 3}
1.1.5. Fonctions d'accès¶
Les fonctions d'accès aux composantes d'un dictionnaire sont : get, items, keys et values
get(key)
- Récupère la valeur d'une clé sans erreur. si clé absente (retourne
Noneou valeur par défaut) - Exemple :
d.get('clé')
- Récupère la valeur d'une clé sans erreur. si clé absente (retourne
keys()
- Liste de toutes les clés
- Exemple :
d.keys()
values()
- Liste de toutes les valeurs
- Exemple :
d.values()
items()
- Définition : Liste de tuples (clé, valeur)
- Exemple :
d.items()
d = dict.fromkeys(['mm', 'g' , 'ms'], 0.001)
print(f"get clé existante : d('mm') = {d.get('mm')}" ) # get clé existante
print(f"get clé non existante : d('cm') = {d.get('cm')}" ) # get clé non existante retourne None
print(f"get valeur défaut : d('cm') = {d.get('cm',0.1)}" ) # get clé non existante retourne 0.1 par défaut
print('\nliste des clés :', d.keys())
print('liste des valeurs :', d.values())
print('liste des entrées :', d.items())
print(f"\n{d = }") # aucune des 4 fonctions ne modifie d
get clé existante : d('mm') = 0.001
get clé non existante : d('cm') = None
get valeur défaut : d('cm') = 0.1
liste des clés : dict_keys(['mm', 'g', 'ms'])
liste des valeurs : dict_values([0.001, 0.001, 0.001])
liste des entrées : dict_items([('mm', 0.001), ('g', 0.001), ('ms', 0.001)])
d = {'mm': 0.001, 'g': 0.001, 'ms': 0.001}
1.1.6. autres fonctions¶
+ len(dict)
+ list(dict)
+ key in dict
+ iter(dict)
# on reprend l'exemple sur les unités (sous et multiple)
millier = dict.fromkeys(['km', 't' , 'h'], 1000) # milliers : km, tonne, et heure à corriger en 3600
millieme = dict.fromkeys(['mm', 'g' , 'ms'], 0.001) # millièmes : mm, gramme milliseconde
centaine = dict.fromkeys(['hm', 'q' , 'min'], 100) # centaines : hectomètre, quintal, min à corriger en 60 s
centieme = dict.fromkeys(['cm', 'dag', 'cs'], 0.01) # centièmes : cm, décagramme, cs
units = millier | centaine | millieme | centieme
units['h'] = 3600
units['min'] = 60
print('km' in units)
print(1000 in units.values())
print(units.keys())
print(units.values())
print(units.items())
print(units.get('km'))
True
True
dict_keys(['km', 't', 'h', 'hm', 'q', 'min', 'mm', 'g', 'ms', 'cm', 'dag', 'cs'])
dict_values([1000, 1000, 3600, 100, 100, 60, 0.001, 0.001, 0.001, 0.01, 0.01, 0.01])
dict_items([('km', 1000), ('t', 1000), ('h', 3600), ('hm', 100), ('q', 100), ('min', 60), ('mm', 0.001), ('g', 0.001), ('ms', 0.001), ('cm', 0.01), ('dag', 0.01), ('cs', 0.01)])
1000
On peut aussi faire appel à la fonction standard len afin de déterminer le nombre d'éléments contenus dans le dictionnaire :
print( len(units) )
12
On peut faire appel à la fonction clear si l'on veut vider le dictionnaire de tous ses éléments. On peut aussi retirer un élément d'un dictionnaire à l'aide de l'énoncé del :
d = dict(zip('ijk','xyz'))
print(d)
del d['j']
print(d)
d.clear()
print(d)
{'i': 'x', 'j': 'y', 'k': 'z'}
{'i': 'x', 'k': 'z'}
{}
Et on peut faire appel à la fonction get (au lieu de l'opérateur []), si l'on n'est pas certain que le dictionnaire possède une certaine clé. Par exemple :
d = {}
d['pi'] = 3.14159265358979
x = d.get('e' , 2.7183) # retourne par défaut 2.7 sans modifier d
y = d.get('pi', 3.1416) # retourne par défaut 2.7 sans modifier d
print(f'{x = }\n{y = }\n{d = }')
x = 2.7183
y = 3.14159265358979
d = {'pi': 3.14159265358979}
Aucun commentaire:
Enregistrer un commentaire