web-dev-qa-db-fra.com

Comment utiliser la notation par points pour dict en python?

Je suis très novice en python et j'aimerais pouvoir utiliser la notation . pour accéder aux valeurs de dict

Disons que j'ai test comme ceci:

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

Mais j'aimerais pouvoir faire test.name pour obtenir value. Enfait je l’ai fait en surchargeant la méthode __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 fais:

test.name // I get value.

Mais le problème, c’est que lorsque j’imprime uniquement test, j’obtiens l’erreur suivante:

'Sorry no key matches'

Pourquoi cela arrive-t-il?

36
batman

Cette fonctionnalité déjà existe dans les bibliothèques standard , je vous recommande donc d'utiliser simplement 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 sont réalisés avec un accès d'attribut standard, c'est-à-dire que vous pouvez utiliser des instructions telles que n.key = val et del n.key

Pour revenir à un dict à nouveau:

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

Les clés de votre dict doivent être string identifiers pour que l'accès aux attributs fonctionne correctement. 

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

57
wim

__getattr__ est utilisé comme solution de secours lorsque toutes les autres règles de recherche d'attribut ont échoué. Lorsque vous essayez "d'imprimer" votre objet, Python recherche une méthode __repr__ et, puisque vous ne l'implémentez pas dans votre classe, il appelle finalement __getattr__ (oui, les méthodes Python contiennent également des attributs). Vous ne devez pas supposer avec quelle clé getattr sera appelée, et le plus important, __getattr__ doit générer un AttributeError s'il ne peut pas résoudre key.

Remarque: n'utilisez pas self.__dict__ pour un accès attributaire ordinaire, utilisez simplement la notation d'attribut simple: 

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 pas d’autre responsabilité (et que votre version de Python est> = 2.6 et que vous n’avez pas besoin de prendre en charge les versions antérieures), vous pouvez simplement utiliser un nom nommé: http://docs.python.org/2/ library/collections.html # collections.namedtuple

4

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)

3
Yann

Vous devez faire attention lorsque vous utilisez __getattr__, car il utilise de nombreuses fonctionnalités Python intégrées.

Essayez quelque chose comme ça ...

class JuspayObject:

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

    def __getattr__(self, key):
        # First, try to return from _response
        try:
            return self.__dict__['_response'][key]
        except KeyError:
            pass
        # If that fails, return default behavior so we don't break Python
        try:
            return self.__dict__[key]
        except KeyError:
            raise AttributeError, key

>>> j = JuspayObject({'foo': 'bar'})
>>> j.foo
'bar'
>>> j
<__main__.JuspayObject instance at 0x7fbdd55965f0>
2
Aya

Ajoutez une méthode __repr__() à la classe afin de pouvoir personnaliser le texte à afficher. 

print text

En savoir plus ici: http://www.diveintopython.net/object_oriented_framework/special_class_methods2.html

1
user2286078

En plus de cette réponse , on peut ajouter un support pour les dict imbriqués:

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
0
Michael H.