142 votes

Définir les attributs d'un dictionnaire en python

Est-il possible de créer un objet à partir d'un dictionnaire en python de telle sorte que chaque clé soit un attribut de cet objet ?

Quelque chose comme ça :

 dict = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }

 e = Employee( dict ) 
 print e.name # Oscar 
 print e.age + 10 # 42 

Je pense que ce serait plutôt l'inverse de cette question : Dictionnaire Python à partir des champs d'un objet

216voto

Ian Clelland Points 15066

Bien sûr, quelque chose comme ça :

class Employee(object):
    def __init__(self, initial_data):
        for key in initial_data:
            setattr(self, key, initial_data[key])

Mise à jour

Comme le suggère Brent Nash, vous pouvez rendre cela plus flexible en autorisant également les arguments de type mot-clé :

class Employee(object):
    def __init__(self, *initial_data, **kwargs):
        for dictionary in initial_data:
            for key in dictionary:
                setattr(self, key, dictionary[key])
        for key in kwargs:
            setattr(self, key, kwargs[key])

Alors vous pouvez l'appeler comme ceci :

e = Employee({"name": "abc", "age": 32})

ou comme ça :

e = Employee(name="abc", age=32)

ou même comme ça :

employee_template = {"role": "minion"}
e = Employee(employee_template, name="abc", age=32)

50voto

Mike Graham Points 22480

Définir des attributs de cette manière n'est presque certainement pas la meilleure façon de résoudre un problème. Soit :

  1. Vous savez à l'avance ce que doivent être tous les champs. Dans ce cas, vous pouvez définir tous les attributs de manière explicite. Cela ressemblerait à

    class Employee(object):
        def __init__(self, name, last_name, age):
            self.name = name
            self.last_name = last_name
            self.age = age
    
    d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
    e = Employee(**d) 
    
    print e.name # Oscar 
    print e.age + 10 # 42 

    ou

  2. Vous ne savez pas à l'avance ce que doivent être tous les champs. Dans ce cas, vous devriez stocker les données sous forme de dict au lieu de polluer l'espace de noms des objets. Les attributs sont destinés à un accès statique. Ce cas ressemblerait à

    class Employee(object):
        def __init__(self, data):
            self.data = data
    
    d = {'name': 'Oscar', 'last_name': 'Reyes', 'age':32 }
    e = Employee(d) 
    
    print e.data['name'] # Oscar 
    print e.data['age'] + 10 # 42 

Une autre solution qui est fondamentalement équivalente au cas 1 est d'utiliser une collections.namedtuple . Voir la réponse de Van pour savoir comment mettre cela en œuvre.

22voto

Dave Kirby Points 12310

Vous pouvez accéder aux attributs d'un objet avec __dict__ et appeler la méthode de mise à jour :

>>> class Employee(object):
...     def __init__(self, _dict):
...         self.__dict__.update(_dict)
... 

>>> dict = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }

>>> e = Employee(dict)

>>> e.name
'Oscar'

>>> e.age
32

20voto

RufusVS Points 53

Pourquoi ne pas simplement utiliser les noms d'attributs comme clés d'un dictionnaire ?

class StructMyDict(dict):

     def __getattr__(self, name):
         try:
             return self[name]
         except KeyError as e:
             raise AttributeError(e)

     def __setattr__(self, name, value):
         self[name] = value

Vous pouvez initialiser avec des arguments nommés, une liste de tuples, ou un dictionnaire, ou encore des affectations d'attributs individuels, par exemple :

nautical = StructMyDict(left = "Port", right = "Starboard") # named args

nautical2 = StructMyDict({"left":"Port","right":"Starboard"}) # dictionary

nautical3 = StructMyDict([("left","Port"),("right","Starboard")]) # tuples list

nautical4 = StructMyDict()  # fields TBD
nautical4.left = "Port"
nautical4.right = "Starboard"

for x in [nautical, nautical2, nautical3, nautical4]:
    print "%s <--> %s" % (x.left,x.right)

Au lieu de générer une erreur d'attribut, vous pouvez également renvoyer None pour les valeurs inconnues. (Une astuce utilisée dans la classe de stockage web2py)

9voto

van Points 18052

Je pense que cette réponse utilisant settattr sont la solution si vous avez vraiment besoin de supporter dict .

Mais si Employee est juste une structure à laquelle vous pouvez accéder avec la syntaxe point ( .name ) au lieu de la syntaxe dict ( ['name'] ), vous pouvez utiliser namedtuple comme ça :

from collections import namedtuple

Employee = namedtuple('Employee', 'name age')
e = Employee('noname01', 6)
print e
#>> Employee(name='noname01', age=6)

# create Employee from dictionary
d = {'name': 'noname02', 'age': 7}
e = Employee(**d)
print e
#>> Employee(name='noname02', age=7)
print e._asdict()
#>> {'age': 7, 'name': 'noname02'}

Vous avez _asdict() pour accéder à toutes les propriétés en tant que dictionnaire, mais vous ne peut pas ajouter des attributs supplémentaires plus tard, seulement pendant la construction.

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