De l’intérêt des tuples comme clé de dictionnaire


On peut utiliser n’importe quel objet hashable comme clé de dictionnaire en Python, pas uniquement des strings. Donc des entiers bien entendu, mais également, et c’est rarement utilisé, des tuples.

Imaginez que vous ayez une structures de données ainsi initialisée :

from random import choice, randint
 
tags = ('personne', 'animal', 'objet')
depart = {}
 
depart = {'%s_%s' % (choice(tags), randint(0, 10)): None for x in range(10)}

Cela donne quelque chose comme ça :

{u'personne_6': None,
 u'personne_5': None,
 u'objet_9': None,
 u'objet_6': None,
 u'objet_4': None,
 u'personne_8': None,
 u'objet_2': None,
 u'objet_0': None,
 u'animal_8': None}

On voit que les clés ont ici une valeur sémantique importante : elles sont porteuses de sens.

Si vous voulez la liste des nombres utilisés, il va vous falloir changer votre structure de données : en avoir plusieurs séparées, probablement. Ou alors faire de la manipulation de chaîne à base de split() et de casting.

Par contre, si vous utilisez un tuple comme clé, vous avez le même format pour votre dictionnaire depart, avec les mêmes possibilités, mais en plus un accès aux clés plus complet.

Déjà le code de génération est plus simple :

depart = {(choice(tags), randint(0, 10)): None for x in range(10)}

Ce qui donne :

{(u'animal', 2): None,
 (u'personne', 5): None,
 (u'personne', 4): None,
 (u'objet', 6): None,
 (u'objet', 10): None,
 (u'animal', 7): None,
 (u'animal', 1): None,
 (u'animal', 10): None,
 (u'personne', 8): None}

Mais en prime, on peut faire ça :

for (tag, number), value in depart.items():
    print tag, number, value
 
## animal 2 None
## personne 5 None
## personne 4 None
## objet 6 None
## objet 10 None
## animal 7 None
## animal 1 None
## animal 10 None
## personne 8 None

Bref, quand vos clés ont une valeur sémantique importante, pensez à utiliser des tuples, voir carrément, un namedtuple, qui est une structure de données trop souvent ignorée alors qu’elle est très puissante, et peut remplacer bien des classes conteneurs.

8 thoughts on “De l’intérêt des tuples comme clé de dictionnaire

  • Krypted

    Tiens, du coup je suis en train de me dire que ça peut être pratique quand on veut un tableau à double entrée.

    Au lieu d’avoir une imbrication de listes

    grid = [[0,0,0],
            [1,1,1],
            [2,2,2]]

    on a un simple dictionnaire.

    grid = {(0,0):0,
            (0,1):0
              ...
            }

    bon la déclaration est plus chiante mais pour l’accès c’est plus simple.
    Je me demande ce que ça donne au niveau des performances.
    Vous en pensez quoi ?

  • Sam Post author

    Ca dépend de l’usage. Si tu as besoin d’une correspondance entre les deux premières valeurs et la dernière, oui.

    Si c’est juste pour itérer, autant faire :

    for a, b, c in grid:

    Sur ta grid originale.

  • plx

    J’avoue m’y vautrer avec délectation comme un cochon dans la boue depuis longtemps, avec des clés qui sont des couples/tuples (x,y) – valeurs réelles ! – pour traiter des données géographiques et ça marche du feu de Dieu !

  • kontre

    @Krypted: ton truc esst pratique dans le cas où tu as une grille avec peu de trucs dessus, tu ne vas stocker que les points où il y a quelque chose et renvoyer une valeur par défaut dans les autres (un defaultdic le fait pour toi).

    @plx: tu n’as jamais de problème d’arrondi ou de précision de calcul en indexant pas des nombres réels ?

    Edit: Au passage, pour les tableaux de nombres 2D (ou plus) j’utiliserais numpy, c’est plus efficace ausi bien en vitesse qu’en mémoire (une fois que la lib est chargée…)

  • plx

    @kontre : des problèmes d’arrondis et/ou liés à la précision des données ? Bien sûr que si !!! Des dictionnaires avec, comme clé, des coordonnées (x,y) m’aident, justement, à résoudre ce genre de problèmes (précision, arrondis, …)

  • kontre

    Justement, si (x, y) = (1.4, 0.2) et que tu cherches le point (1.399999997, 0.20000000003), tu ne vas pas le trouver. Ou bien tu utilises des entiers seulement (mais tu as dit “réels”) ?

  • Sam Post author

    Je pense qu’il veut dire qu’il utilise un tuple (int, int), avec le premier présentant la partie entière, et le second pour les chiffres après la virgule.

Comments are closed.

Des questions Python sans rapport avec l'article ? Posez-les sur IndexError.