Je trouve plus pratique d'accéder aux touches dict comme obj.foo
au lieu de obj['foo']
, j'ai donc écrit cet extrait:
class AttributeDict(dict):
def __getattr__(self, attr):
return self[attr]
def __setattr__(self, attr, value):
self[attr] = value
Cependant, je suppose qu'il doit y avoir une raison pour laquelle Python ne fournit pas cette fonctionnalité prête à l'emploi. Quelles seraient les mises en garde et les pièges de l'accès aux clés dict de cette manière?
python
dictionary
syntax
attributes
Izz ad-Din Ruhulessin
la source
la source
collections.namedtuple
est très utile pour cela.easydict.EasyDict
Réponses:
La meilleure façon de procéder est:
Quelques pros:
.keys()
fonctionne très bien. À moins que - bien sûr - vous leur attribuez une valeur, voir ci-dessous)AttributeError
au lieu deKeyError
Les inconvénients:
.keys()
ne pas fonctionner très bien si elles seront écrasés par des données entrantesE1123(unexpected-keyword-arg)
etE1103(maybe-no-member)
Une brève explication sur la façon dont cela fonctionne
__dict__
.__dict__
être "juste un dict simple", donc nous pouvons assigner n'importe quelle sous-classe dedict()
au dictionnaire interne.AttrDict()
instance dans laquelle nous instancions (comme nous le sommes__init__
).super()
la__init__()
méthode, nous nous sommes assurés qu'elle se comporte (déjà) exactement comme un dictionnaire, car cette fonction appelle tout le code d' instanciation du dictionnaire .Une des raisons pour lesquelles Python ne fournit pas cette fonctionnalité prête à l'emploi
Comme indiqué dans la liste des "inconvénients", cela combine l'espace de noms des clés stockées (qui peuvent provenir de données arbitraires et / ou non fiables!) Avec l'espace de noms des attributs de méthode dict intégrés. Par exemple:
la source
.
, vous ne pouvez pas enfreindre les règles du langage :) Et je ne voudraisAttrDict
pas convertir automatiquement les champs contenant de l'espace en quelque chose de différent.Vous pouvez avoir tous les caractères de chaîne légaux dans le cadre de la clé si vous utilisez la notation de tableau. Par exemple,
obj['!#$%^&*()_']
la source
What would be the caveats and pitfalls of accessing dict keys in this manner?
(en tant qu'attributs), et la réponse est que la plupart des caractères montrés ici ne seraient pas utilisables.De cette autre question SO il y a un excellent exemple d'implémentation qui simplifie votre code existant. Que diriez-vous:
Beaucoup plus concis et ne laisse aucune place à une corruption supplémentaire dans votre
__getattr__
et__setattr__
fonctionne à l'avenir.la source
d = AttributeDict(foo=1)
.d.bar = 1
l'attribut bar est stocké dans l' attribut dict mais pas dans le dict lui-même. l'impressiond
ne montre que l'élément foo.d = AttributeDict(foo=1);d.bar = 1;print d
=>{'foo': 1, 'bar': 1}
Fonctionne pour moi!__getattr__
méthode qui déclenche unAttributeError
si l'attribut donné n'existe pas, sinon des choses commegetattr(obj, attr, default_value)
ne fonctionnent pas (c'est-à-dire ne retournent pasdefault_value
siattr
n'existe pasobj
)Où je réponds à la question posée
Pourquoi Python ne le propose-t-il pas prêt à l'emploi?
Je soupçonne que cela a à voir avec le Zen de Python : "Il devrait y avoir une - et de préférence une seule - façon évidente de le faire." Cela créerait deux façons évidentes d'accéder aux valeurs des dictionnaires:
obj['key']
etobj.key
.Mises en garde et pièges
Il s'agit notamment d'un possible manque de clarté et de confusion dans le code. c'est-à-dire que ce qui suit pourrait être déroutant pour quelqu'un d' autre qui va maintenir votre code à une date ultérieure, ou même pour vous, si vous n'y revenez pas pendant un certain temps. Encore une fois, de Zen : "La lisibilité compte!"
Si
d
est instancié ouKEY
est défini oud[KEY]
est attribué loin de l'endroit où ild.spam
est utilisé, cela peut facilement entraîner une confusion quant à ce qui est fait, car ce n'est pas un idiome couramment utilisé. Je sais que cela pourrait me confondre.De plus, si vous modifiez la valeur de la
KEY
manière suivante (mais que vous manquez de changerd.spam
), vous obtenez maintenant:OMI, ne vaut pas l'effort.
Autres éléments
Comme d'autres l'ont noté, vous pouvez utiliser n'importe quel objet lavable (pas seulement une chaîne) comme clé de dictée. Par exemple,
est légal, mais
n'est pas. Cela vous donne accès à toute la gamme de caractères imprimables ou d'autres objets hachables pour vos clés de dictionnaire, que vous n'avez pas lorsque vous accédez à un attribut d'objet. Cela rend possible une magie telle qu'une métaclasse d'objet mis en cache, comme la recette du livre de recettes Python (Ch. 9) .
Où j'éditorialise
Je préfère l'esthétique de
spam.eggs
Overspam['eggs']
(je pense que ça a l'air plus propre), et j'ai vraiment commencé à avoir envie de cette fonctionnalité quand j'ai rencontré lenamedtuple
. Mais la commodité de pouvoir faire ce qui suit l'emporte.Ceci est un exemple simple, mais je me retrouve souvent à utiliser des dict dans des situations différentes de celles que j'utiliserais la
obj.key
notation (c'est-à-dire lorsque j'ai besoin de lire les préférences dans un fichier XML). Dans d'autres cas, lorsque je suis tenté d'instancier une classe dynamique et de gifler certains attributs pour des raisons esthétiques, je continue à utiliser un dict pour la cohérence afin d'améliorer la lisibilité.Je suis sûr que l'OP a résolu cela depuis longtemps à sa satisfaction, mais s'il veut toujours cette fonctionnalité, alors je lui suggère de télécharger l'un des packages de pypi qui le fournit:
Bunch est celui que je connais le mieux. Sous-classe dedict
, vous avez donc toutes ces fonctionnalités.AttrDict semble également être assez bon, mais je ne le connais pas aussi bien et je n'ai pas parcouru la source avec autant de détails que j'ai Bunch .Cependant, afin d'améliorer la lisibilité de son code, je lui recommande fortement de ne pas mélanger ses styles de notation. S'il préfère cette notation, il doit simplement instancier un objet dynamique, y ajouter les attributs souhaités et l'appeler un jour:
Où je mets à jour, pour répondre à une question de suivi dans les commentaires
Dans les commentaires (ci-dessous), Elmo demande:
Bien que je n'aie jamais utilisé ce cas d'utilisation (encore une fois, j'ai tendance à utiliser imbriqué
dict
, pour des raisons de cohérence), le code suivant fonctionne:la source
Caveat emptor: Pour certaines raisons, des classes comme celle-ci semblent rompre le package de multitraitement. Je me suis juste débattu avec ce bogue pendant un certain temps avant de trouver ce SO: Trouver une exception dans le multiprocessing python
la source
Vous pouvez extraire une classe de conteneur pratique de la bibliothèque standard:
pour éviter d'avoir à copier autour des bits de code. Pas d'accès au dictionnaire standard, mais facile à récupérer si vous le voulez vraiment. Le code dans argparse est simple,
la source
types.SimpleNamespace
docs.python.org/dev/library/types.html#types.SimpleNamespaceEt si vous vouliez une clé qui était une méthode, comme
__eq__
ou__getattr__
?Et vous ne pourriez pas avoir une entrée qui ne commence pas par une lettre, donc l'utilisation
0343853
comme clé est supprimée.Et si vous ne vouliez pas utiliser de chaîne?
la source
pickle.dump
utilisations__getstate__
les tuples peuvent être utilisés des touches dict. Comment accéderiez-vous au tuple dans votre construction?
De plus, namedtuple est une structure pratique qui peut fournir des valeurs via l'accès aux attributs.
la source
Que diriez-vous de Prodict , la petite classe Python que j'ai écrite pour les gouverner tous :)
De plus, vous obtenez l'achèvement automatique du code , les instanciations d'objets récursifs et la conversion de type automatique !
Vous pouvez faire exactement ce que vous avez demandé:
Exemple 1: indication de type
Exemple 2: conversion de type automatique
la source
Cela ne fonctionne pas en général. Toutes les clés de dict valides ne font pas des attributs adressables ("la clé"). Vous devrez donc être prudent.
Les objets Python sont tous essentiellement des dictionnaires. Je doute donc qu'il y ait beaucoup de performances ou d'autres pénalités.
la source
Cela ne répond pas à la question d'origine, mais devrait être utile pour les personnes qui, comme moi, se retrouvent ici lors de la recherche d'une bibliothèque qui fournit cette fonctionnalité.
Addict, c'est une grande bibliothèque pour cela: https://github.com/mewwts/addict, il prend en charge de nombreuses préoccupations mentionnées dans les réponses précédentes.
Un exemple de la documentation:
Avec addict:
la source
Je me suis retrouvé à me demander quel était l'état actuel des "clés dict comme attr" dans l'écosystème python. Comme l'ont souligné plusieurs commentateurs, ce n'est probablement pas quelque chose que vous voulez rouler à partir de zéro , car il y a plusieurs pièges et pistolets, dont certains sont très subtils. De plus, je ne recommanderais pas d'utiliser
Namespace
comme classe de base, j'ai été dans cette voie, ce n'est pas joli.Heureusement, il existe plusieurs packages open source fournissant cette fonctionnalité, prêts à être installés! Malheureusement, il existe plusieurs packages. Voici un synopsis, en décembre 2019.
Contenders (le plus récent commit to master | #commits | #contribs | coverage%):
Plus entretenu ou sous-entretenu:
Je recommande actuellement munch ou addict . Ils ont le plus de validations, de contributeurs et de versions, suggérant une base de code open source saine pour chacun. Ils ont le fichier readme.md le plus net, une couverture à 100% et un ensemble de tests de bonne qualité.
Je n'ai pas de chien dans cette course (pour l'instant!), En plus d'avoir roulé mon propre code dict / attr et perdu une tonne de temps parce que je n'étais pas au courant de toutes ces options :). Je peux contribuer à Addict / Munch à l'avenir car je préférerais voir un paquet solide plutôt qu'un tas de paquets fragmentés. Si vous les aimez, contribuez! En particulier, on dirait que munch pourrait utiliser un badge codecov et addict pourrait utiliser un badge de version python.
pros de la toxicomanie:
toxicomane contre:
typing.Dict
si vousfrom addict import Dict
munch pros:
grignoter les inconvénients:
Où j'éditorialise
Il y a plusieurs lunes, lorsque j'utilisais des éditeurs de texte pour écrire du python, sur des projets avec seulement moi ou un autre développeur, j'aimais le style de dict-attrs, la possibilité d'insérer des clés en déclarant simplement
foo.bar.spam = eggs
. Maintenant, je travaille en équipe et j'utilise un IDE pour tout, et je me suis éloigné de ce type de structures de données et de typage dynamique en général, en faveur de l'analyse statique, des techniques fonctionnelles et des indices de type. J'ai commencé à expérimenter cette technique, en sous-classant Pstruct avec des objets de ma propre conception:Cela vous donne un objet qui se comporte toujours comme un dict, mais vous permet également d'accéder à des clés comme des attributs, d'une manière beaucoup plus rigide. L'avantage ici est que je (ou les malheureux consommateurs de votre code) sais exactement quels champs peuvent et ne peuvent pas exister, et l'EDI peut compléter automatiquement les champs. Sous-classer également vanilla
dict
signifie que la sérialisation json est facile. Je pense que la prochaine évolution de cette idée serait un générateur de protobuf personnalisé qui émet ces interfaces, et une bonne option est que vous obtenez des structures de données multilingues et IPC via gRPC presque gratuitement.Si vous décidez d'aller avec des attr-dicts, il est essentiel de documenter quels champs sont attendus, pour votre propre santé mentale (et celle de vos coéquipiers).
N'hésitez pas à éditer / mettre à jour ce post pour le garder récent!
la source
addict
pas d'exceptions lorsque vous orthographiez mal un attribut, car il en retournera un nouveauDict
(cela est nécessaire pour que foo.abc = 'bar' fonctionne).Voici un bref exemple d'enregistrements immuables utilisant la fonction intégrée
collections.namedtuple
:et un exemple d'utilisation:
la source
Juste pour ajouter de la variété à la réponse, sci-kit learn a implémenté ceci comme
Bunch
:Tout ce dont vous avez besoin est d'obtenir les méthodes
setattr
etgetattr
- lesgetattr
vérifications des clés dict et le passage à la vérification des attributs réels. Ilsetstaet
s'agit d'un correctif pour le correctif de décapage / décapage des "grappes" - en cas de désintérêt, consultez https://github.com/scikit-learn/scikit-learn/issues/6196la source
Pas besoin d'écrire les vôtres car setattr () et getattr () existent déjà.
L'avantage des objets de classe entre probablement en jeu dans la définition et l'héritage des classes.
la source
J'ai créé cela en fonction de l'entrée de ce fil. Cependant, je dois utiliser odict, j'ai donc dû remplacer get et définir attr. Je pense que cela devrait fonctionner pour la majorité des utilisations spéciales.
L'utilisation ressemble à ceci:
La classe:
C'est un modèle assez cool déjà mentionné dans le fil, mais si vous voulez simplement prendre un dict et le convertir en un objet qui fonctionne avec la saisie semi-automatique dans un IDE, etc.:
la source
Apparemment, il existe maintenant une bibliothèque pour cela - https://pypi.python.org/pypi/attrdict - qui implémente cette fonctionnalité exacte ainsi que la fusion récursive et le chargement json. Ça vaut peut-être le coup d'oeil.
la source
C'est ce que j'utilise
la source
namedtuple('Args', list(args.keys()))(**args)
Vous pouvez le faire en utilisant cette classe que je viens de créer. Avec cette classe, vous pouvez utiliser l'
Map
objet comme un autre dictionnaire (y compris la sérialisation json) ou avec la notation par points. J'espère vous aider:Exemples d'utilisation:
la source
dict
méthodes, par exemple:m=Map(); m["keys"] = 42; m.keys()
giveTypeError: 'int' object is not callable
.field/attribute
et non unmethod
, mais si vous attribuez une méthode à la place un nombre, vous pouvez accéder à cette méthode avecm.method()
.Permettez-moi de publier une autre implémentation, qui s'appuie sur la réponse de Kinvais, mais intègre des idées de AttributeDict proposées dans http://databio.org/posts/python_AttributeDict.html .
L'avantage de cette version est qu'elle fonctionne également pour les dictionnaires imbriqués:
la source
la source
La solution est:
la source
Comme @Henry le suggère, une des raisons pour lesquelles l'accès en pointillé ne peut pas être utilisé dans les dict est qu'il limite les noms de clés dict aux variables valides pour python, limitant ainsi tous les noms possibles.
Les exemples suivants expliquent pourquoi l'accès en pointillé ne serait pas utile en général, étant donné un dict
d
:Validité
Les attributs suivants ne seraient pas valides en Python:
Style
Les conventions PEP8 imposeraient une contrainte douce sur la dénomination des attributs:
A. Noms de mots-clés réservés (ou fonction intégrée):
B. La règle de l'affaire méthodes et les noms de variables :
Parfois, ces préoccupations sont soulevées dans des bibliothèques comme pandas , ce qui permet d'accéder en pointillé aux colonnes DataFrame par leur nom. Le mécanisme par défaut pour résoudre les restrictions de dénomination est également la notation matricielle - une chaîne entre crochets.
Si ces contraintes ne s'appliquent pas à votre cas d'utilisation, il existe plusieurs options sur les structures de données à accès pointillé .
la source
Vous pouvez utiliser dict_to_obj https://pypi.org/project/dict-to-obj/ Il fait exactement ce que vous avez demandé
la source
.idea
et tout fichier spécifique à l'utilisateur ou généré par IDE dans votre fichier.gitignore
.Ce n'est pas une «bonne» réponse, mais je pensais que c'était astucieux (il ne gère pas les dictés imbriqués sous leur forme actuelle). Enveloppez simplement votre dict dans une fonction:
Vous avez maintenant une syntaxe légèrement différente. Pour accéder aux éléments dict comme le font les attributs
f.key
. Pour accéder aux éléments dict (et aux autres méthodes dict) de la manière habituelle, faitesf()['key']
et nous pouvons facilement mettre à jour le dict en appelant f avec des arguments de mots clés et / ou un dictionnaireExemple
Et voilà. Je serai heureux si quelqu'un suggère des avantages et des inconvénients de cette méthode.
la source
Comme l'a noté Doug, il existe un package Bunch que vous pouvez utiliser pour obtenir la
obj.key
fonctionnalité. En fait, il existe une nouvelle version appeléeNeoBunch
Il a cependant une excellente fonctionnalité pour convertir votre dict en objet NeoBunch via sa fonction neobunchify . J'utilise beaucoup de modèles Mako et transmettre des données en tant qu'objets NeoBunch les rend beaucoup plus lisibles, donc si vous finissez par utiliser un dict normal dans votre programme Python mais que vous voulez la notation par points dans un modèle Mako, vous pouvez l'utiliser de cette façon:
Et le modèle Mako pourrait ressembler à:
la source
La façon la plus simple est de définir une classe appelons-la namespace. qui utilise l'objet dict .update () sur le dict. Ensuite, le dict sera traité comme un objet.
la source