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?
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.
__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
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)
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>
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
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