100 votes

Python defaultdict et lambda

Dans le code de quelqu'un d'autre, j'ai lu les deux lignes suivantes :

x = defaultdict(lambda: 0)
y = defaultdict(lambda: defaultdict(lambda: 0))

Comme l'argument de defaultdict est une fabrique par défaut, je pense que la première ligne signifie que lorsque j'appelle x[k] pour une clé k inexistante (comme une instruction du type v=x[k]), la paire clé-valeur (k,0) sera automatiquement ajoutée au dictionnaire, comme si l'instruction x[k]=0 était d'abord exécutée. Ai-je raison ?

Et qu'en est-il de y ? Il semble que la fabrique par défaut créera un defaultdict avec 0 par défaut. Mais que cela signifie-t-il concrètement ? J'ai essayé de jouer avec cela dans la console Python, mais je n'ai pas réussi à comprendre exactement ce que c'est.

88voto

larsmans Points 167484

Je pense que la première ligne signifie que lorsque j'appelle x[k] pour une clé inexistante k (comme une instruction du type v=x[k]), la paire clé-valeur (k,0) sera automatiquement ajoutée au dictionnaire, comme si l'instruction x[k]=0 était d'abord exécutée.

C'est exact. Cela s'écrit de manière plus idiomatique

x = defaultdict(int)

Dans le cas de y, lorsque vous faites y["ham"]["spam"], la clé "ham" est insérée dans y si elle n'existe pas. La valeur associée à celle-ci devient un defaultdict dans lequel "spam" est automatiquement inséré avec une valeur de 0.

Autrement dit, y est une sorte de defaultdict "à deux niveaux". Si "ham" not in y, alors évaluer y["ham"]["spam"] revient à faire

y["ham"] = {}
y["ham"]["spam"] = 0

en termes de dict ordinaire.

12voto

Andrew Clark Points 77748

Vous avez raison pour ce que le premier fait. En ce qui concerne y, cela créera un defaultdict avec un 0 par défaut lorsque une clé n'existe pas dans y, donc vous pouvez penser à ceci comme un dictionnaire imbriqué. Considérez l'exemple suivant:

y = defaultdict(lambda: defaultdict(lambda: 0))
print y['k1']['k2']   # 0
print dict(y['k1'])   # {'k2': 0}

Pour créer une structure de dictionnaire imbriquée équivalente sans defaultdict, vous aurez besoin de créer un dict interne pour y['k1'] puis définir y['k1']['k2'] à 0, mais defaultdict fait tout cela en arrière-plan lorsqu'il rencontre des clés qu'il n'a pas vues:

y = {}
y['k1'] = {}
y['k1']['k2'] = 0

La fonction suivante peut aider à jouer avec cela sur un interpréteur pour améliorer votre compréhension:

def to_dict(d):
    if isinstance(d, defaultdict):
        return dict((k, to_dict(v)) for k, v in d.items())
    return d

Cela renverra l'équivalent dict du defaultdict imbriqué, ce qui est beaucoup plus facile à lire. Par exemple:

>>> y = defaultdict(lambda: defaultdict(lambda: 0))
>>> y['a']['b'] = 5
>>> y
defaultdict( at 0xb7ea93e4>, {'a': defaultdict( at 0xb7ea9374>, {'b': 5})})
>>> to_dict(y)
{'a': {'b': 5}}

10voto

Triptych Points 70247

defaultdict prend un callable à zéro argument dans son constructeur, qui est appelé lorsque la clé n'est pas trouvée, comme vous l'avez correctement expliqué.

lambda: 0 retournera bien sûr toujours zéro, mais la méthode préférée pour le faire est defaultdict(int), qui fera la même chose.

Quant à la deuxième partie, l'auteur aimerait créer un nouveau defaultdict(int), ou un dictionnaire imbriqué, chaque fois qu'une clé n'est pas trouvée dans le dictionnaire de niveau supérieur.

5voto

Prashant Pathak Points 91

Toutes les réponses sont suffisantes mais je vais quand même donner la réponse pour ajouter plus d'informations :

"defaultdict nécessite un argument qui est appelable. Le résultat renvoyé par cet objet appelable est la valeur par défaut que le dictionnaire renvoie lorsque vous essayez d'accéder au dictionnaire avec une clé qui n'existe pas."

Voici un exemple

SAMPLE= {'Age':28, 'Salaire':2000}
SAMPLE = defaultdict(lambda:0,SAMPLE)

>>> SAMPLE
defaultdict( at 0x0000000002BF7C88>, {'Salaire': 2000, 'Age': 28})

>>> SAMPLE['Age']----> Cela renverra 28
>>> SAMPLE['Téléphone']----> Cela renverra 0   # vous obtenez 0 en sortie pour une clé inexistante dans SAMPLE

3voto

yongsun Points 35

y = defaultdict(lambda:defaultdict(lambda:0))

il sera utile si vous essayez ceci y['a']['b'] += 1

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X