167 votes

Comment utiliser la notation du point pour le dict en python ?

Je suis très novice en matière de python et j'aimerais pouvoir faire . pour accéder aux valeurs d'un dict .

Disons que j'ai test comme ça :

>>> test = dict()
>>> test['name'] = 'value'
>>> print(test['name'])
value

Mais j'aimerais pouvoir faire test.name pour obtenir value . En fait, je l'ai fait en remplaçant l'option __getattr__ dans ma classe comme ceci :

class JuspayObject:

    def __init__(self,response):
        self.__dict__['_response'] = response

    def __getattr__(self,key): 
        try:
            return self._response[key]
        except KeyError,err:
            sys.stderr.write('Sorry no key matches')

et ça marche ! quand je le fais :

test.name // I get value.

Mais le problème est que lorsque j'imprime juste test seul j'obtiens l'erreur comme :

'Sorry no key matches'

Pourquoi cela se produit-il ?

285voto

wim Points 35274

Cette fonctionnalité est déjà existe dans les bibliothèques standard donc je vous recommande d'utiliser leur classe.

>>> from types import SimpleNamespace
>>> d = {'key1': 'value1', 'key2': 'value2'}
>>> n = SimpleNamespace(**d)
>>> print(n)
namespace(key1='value1', key2='value2')
>>> n.key2
'value2'

L'ajout, la modification et la suppression de valeurs s'effectuent par l'accès habituel aux attributs, c'est-à-dire que vous pouvez utiliser des instructions telles que n.key = val y del n.key .

Revenir à un dictateur :

>>> vars(n)
{'key1': 'value1', 'key2': 'value2'}

Les clés de votre dict doivent être des chaînes de caractères identifiants pour que l'accès aux attributs fonctionne correctement.

L'espace de nom simple a été ajouté dans Python 3.3. Pour les versions plus anciennes du langage, argparse.Namespace a un comportement similaire.

61voto

fortran Points 26495

Je suppose que vous êtes à l'aise en Javascript et que vous voulez emprunter ce type de syntaxe... Je peux vous dire par expérience personnelle que ce n'est pas une bonne idée.

C'est vrai que cela semble moins verbeux et moins ordonné, mais à long terme, c'est tout simplement obscur. Les dicts sont des dicts, et essayer de les faire se comporter comme des objets avec des attributs conduira probablement à de (mauvaises) surprises.

Si vous avez besoin de manipuler les champs d'un objet comme s'il s'agissait d'un dictionnaire, vous pouvez toujours recourir à l'outil interne __dict__ attribut lorsque vous en avez besoin, puis il est explicitement clarifier ce que vous faites. Ou utilisez getattr(obj, 'key') pour tenir compte de la structure d'héritage et des attributs de classe également.

Mais en lisant votre exemple, il semble que vous essayez quelque chose de différent... Comme l'opérateur point va déjà chercher dans le __dict__ sans aucun code supplémentaire.

23voto

Michael H. Points 1377

En plus de cette réponse On peut également ajouter le support des dicts imbriquées :

from types import SimpleNamespace

class NestedNamespace(SimpleNamespace):
    def __init__(self, dictionary, **kwargs):
        super().__init__(**kwargs)
        for key, value in dictionary.items():
            if isinstance(value, dict):
                self.__setattr__(key, NestedNamespace(value))
            else:
                self.__setattr__(key, value)

nested_namespace = NestedNamespace({
    'parent': {
        'child': {
            'grandchild': 'value'
        }
    },
    'normal_key': 'normal value',
})

print(nested_namespace.parent.child.grandchild)  # value
print(nested_namespace.normal_key)  # normal value

Notez que cela ne supporte pas la notation par points pour les dicts qui se trouvent quelque part à l'intérieur de listes, par exemple.

16voto

Yann Points 6909

Pourriez-vous utiliser un nommé tuple ?

from collections import namedtuple
Test = namedtuple('Test', 'name foo bar')
my_test = Test('value', 'foo_val', 'bar_val')
print(my_test)
print(my_test.name)

6voto

bruno desthuilliers Points 10061

__getattr__ est utilisé comme solution de repli lorsque toutes les autres règles de recherche d'attributs ont échoué. Lorsque vous essayez d'"imprimer" votre objet, Python recherche un attribut __repr__ et comme vous ne l'implémentez pas dans votre classe, elle finit par appeler la méthode __getattr__ (oui, en Python, les méthodes sont aussi des attributs). Vous ne devez pas supposer quelle clé getattr sera appelé avec, et, le plus important, __getattr__ doit lever un AttributeError s'il ne peut pas résoudre key .

À titre d'information, n'utilisez pas self.__dict__ pour un accès ordinaire aux attributs, il suffit d'utiliser la notation ordinaire des attributs :

class JuspayObject:

    def __init__(self,response):
        # don't use self.__dict__ here
        self._response = response

    def __getattr__(self,key):
        try:
            return self._response[key]
        except KeyError,err:
            raise AttributeError(key)

Maintenant, si votre classe n'a aucune autre responsabilité (et que votre version de Python est >= 2.6 et que vous n'avez pas besoin de supporter des versions plus anciennes), vous pouvez simplement utiliser un namedtuple : http://docs.python.org/2/library/collections.html#collections.namedtuple

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