J'ai un dictionnaire imbriqué. Existe-t-il un seul moyen de diffuser les valeurs en toute sécurité?
try:
example_dict['key1']['key2']
except KeyError:
pass
Ou peut-être que python a une méthode comme get()
pour le dictionnaire imbriqué?
J'ai un dictionnaire imbriqué. Existe-t-il un seul moyen de diffuser les valeurs en toute sécurité?
try:
example_dict['key1']['key2']
except KeyError:
pass
Ou peut-être que python a une méthode comme get()
pour le dictionnaire imbriqué?
except keyerror:
clause.Réponses:
Vous pouvez utiliser
get
deux fois:Cela reviendra
None
si l'unkey1
ou l' autrekey2
n'existe pas.Notez que cela peut toujours déclencher un
AttributeError
ifexample_dict['key1']
existe mais n'est pas un dict (ou un objet de type dict avec uneget
méthode). Letry..except
code que vous avez publié lèverait un à laTypeError
place s'ilexample_dict['key1']
est désinscriptible.Une autre différence est que les
try...except
court-circuits immédiatement après la première clé manquante. La chaîne d'get
appels ne le fait pas.Si vous souhaitez conserver la syntaxe,
example_dict['key1']['key2']
mais ne voulez pas qu'elle déclenche jamais KeyErrors, vous pouvez utiliser la recette Hasher :Notez que cela renvoie un Hasher vide lorsqu'une clé est manquante.
Depuis
Hasher
une sous-classe dedict
vous pouvez utiliser un Hasher de la même manière que vous pourriez utiliser undict
. Toutes les mêmes méthodes et syntaxe sont disponibles, les Hashers traitent simplement les clés manquantes différemment.Vous pouvez convertir un régulier
dict
en unHasher
comme ceci:et convertissez a
Hasher
en régulierdict
tout aussi facilement:Une autre alternative est de cacher la laideur dans une fonction d'assistance:
Ainsi, le reste de votre code peut rester relativement lisible:
la source
safeget
méthode n'est pas très sûre à bien des égards car elle écrase le dictionnaire d'origine, ce qui signifie que vous ne pouvez pas faire des choses commesafeget(dct, 'a', 'b') or safeget(dct, 'a')
.dct = dct[key]
réaffecte une nouvelle valeur à la variable localedct
. Cela ne modifie pas le dict original (donc le dict original n'est pas affecté parsafeget
.) Si, par contre,dct[key] = ...
avait été utilisé, alors le dict original aurait été modifié. En d'autres termes, en Python, les noms sont liés à des valeurs . L'attribution d'une nouvelle valeur à un nom n'affecte pas l'ancienne valeur (à moins qu'il n'y ait plus de références à l'ancienne valeur, auquel cas (en CPython) il sera récupéré.)safeget
méthode échouera également dans le cas où la clé d'un dict imbriqué existe, mais la valeur est nulle. Il jetteraTypeError: 'NoneType' object is not subscriptable
dans la prochaine itérationVous pouvez également utiliser python réduire :
la source
En combinant toutes ces réponses ici et les petits changements que j'ai apportés, je pense que cette fonction serait utile. c'est sûr, rapide, facilement maintenable.
Exemple :
la source
deep_get({'a': 1}, "a.b")
donneNone
mais je m'attendrais à une exception commeKeyError
ou autre chose.None
àRaise KeyError
S'appuyant sur la réponse de Yoav, une approche encore plus sûre:
la source
Une solution récursive. Ce n'est pas le plus efficace mais je le trouve un peu plus lisible que les autres exemples et il ne repose pas sur des functools.
Exemple
Une version plus raffinée
la source
Bien que l'approche de réduction soit nette et courte, je pense qu'une simple boucle est plus facile à grok. J'ai également inclus un paramètre par défaut.
Pour comprendre comment fonctionnait le réducteur à une ligne, j'ai fait ce qui suit. Mais finalement, l'approche en boucle me semble plus intuitive.
Usage
la source
Je vous suggère d'essayer
python-benedict
.C'est une
dict
sous-classe qui fournit un support de keypath et bien plus encore.Installation:
pip install python-benedict
vous pouvez maintenant accéder aux valeurs imbriquées à l'aide du chemin d'accès :
ou accédez aux valeurs imbriquées à l'aide de la liste des clés :
Il est bien testé et open-source sur GitHub :
https://github.com/fabiocaccamo/python-benedict
la source
d.get('a.b[0].c[-1]')
Une classe simple qui peut encapsuler un dict et récupérer en fonction d'une clé:
Par exemple:
Si la clé n'existe pas, elle retourne
None
par défaut. Vous pouvez remplacer cela en utilisant undefault=
clé dans leFindDict
wrapper - par exemple`:la source
pour une récupération de clé de deuxième niveau, vous pouvez le faire:
la source
Après avoir vu cela pour obtenir des attributs en profondeur, j'ai fait ce qui suit pour obtenir en toute sécurité des
dict
valeurs imbriquées en utilisant la notation par points. Cela fonctionne pour moi parce que mesdicts
objets MongoDB sont désérialisés, donc je sais que les noms de clés ne contiennent pas de.
s. De plus, dans mon contexte, je peux spécifier une valeur de repli falsifiée (None
) que je n'ai pas dans mes données, afin que je puisse éviter le modèle try / except lors de l'appel de la fonction.la source
fallback
n'est pas réellement utilisé dans la fonction..
sep=','
mot - clé arg pour généraliser des conditions données (sep, fallback). Et @denvar, siobj
c'est dire de typeint
après une séquence de réduction, alors obj [nom] lève une TypeError, que j'attrape. Si j'utilisais à la place obj.get (nom) ou obj.get (nom, repli), cela déclencherait une AttributeError, donc de toute façon, je devrais attraper.Encore une autre fonction pour la même chose, renvoie également un booléen pour représenter si la clé a été trouvée ou non et gère certaines erreurs inattendues.
exemple d'utilisation:
la source
Vous pouvez utiliser pydash:
https://pydash.readthedocs.io/en/latest/api.html
la source
Une adaptation de la réponse d'unutbu que j'ai trouvée utile dans mon propre code:
Il génère une entrée de dictionnaire pour key1 s'il n'a pas déjà cette clé afin que vous évitiez l'erreur KeyError. Si vous voulez quand même créer un dictionnaire imbriqué qui inclut ce couplage de clés comme je l'ai fait, cela semble être la solution la plus simple.
la source
Puisque lever une erreur de clé si l'une des clés est manquante est une chose raisonnable à faire, nous ne pouvons même pas la vérifier et l'obtenir aussi simple que cela:
la source
Peu d'amélioration de l'
reduce
approche pour le faire fonctionner avec la liste. Utiliser également le chemin de données sous forme de chaîne divisée par des points au lieu d'un tableau.la source
Une solution que j'ai utilisée qui est similaire au double get mais avec la possibilité supplémentaire d'éviter une TypeError en utilisant la logique if else:
Cependant, plus le dictionnaire est imbriqué, plus cela devient compliqué.
la source
Pour les recherches de dictionnaire imbriquées / JSON, vous pouvez utiliser dictor
pip install dictor
objet dict
pour obtenir les éléments de Lonestar, fournissez simplement un chemin séparé par des points, c.-à-d.
vous pouvez fournir une valeur de secours au cas où la clé ne serait pas dans le chemin
il y a des tonnes d'options supplémentaires que vous pouvez faire, comme ignorer la casse des lettres et utiliser d'autres caractères en plus de '.' comme séparateur de chemin,
https://github.com/perfecto25/dictor
la source
J'ai peu changé cette réponse. J'ai ajouté la vérification si nous utilisons une liste avec des nombres. Alors maintenant, nous pouvons l'utiliser de n'importe quelle manière.
deep_get(allTemp, [0], {})
oudeep_get(getMinimalTemp, [0, minimalTemperatureKey], 26)
etcla source
Il y a déjà beaucoup de bonnes réponses, mais j'ai mis au point une fonction appelée get similar to lodash get in JavaScript land qui prend également en charge l'accès aux listes par index:
la source