web-dev-qa-db-fra.com

Définissez les attributs du dictionnaire dans python

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

Quelque chose comme ça:

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

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

Je pense que ce serait à peu près l'inverse de cette question: dictionnaire Python des champs d'un objet

87
OscarRyz

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 mots clés:

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])

Ensuite, 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)
143
Ian Clelland

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

  1. Vous savez à l'avance tous les champs. Dans ce cas, vous pouvez définir explicitement tous les attributs. 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 ce que tous les champs doivent être à l'avance. Dans ce cas, vous devez stocker les données en tant que dict au lieu de polluer un espace de noms d'objets. Les attributs sont pour l'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 consiste à utiliser un collections.namedtuple. Voir la réponse de van pour savoir comment implémenter cela.

40
Mike Graham

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

>>> 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
13
Dave Kirby

Pourquoi ne pas simplement utiliser des noms d'attribut 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 des affectations d'attribut individuelles, 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)

Alternativement, au lieu de déclencher l'erreur d'attribut, vous pouvez retourner Aucun pour les valeurs inconnues. (Une astuce utilisée dans la classe de stockage web2py)

7
RufusVS

dis par exemple

class A():
    def __init__(self):
        self.x=7
        self.y=8
        self.z="name"

si vous souhaitez définir les attributs à la fois

d = {'x':100,'y':300,'z':"blah"}
a = A()
a.__dict__.update(d)
6
islam ezzat

Je pense que la réponse en utilisant settattr est la voie à suivre si vous avez vraiment besoin de supporter dict.

Mais si l'objet Employee n'est qu'une structure à laquelle vous pouvez accéder avec la syntaxe à points (.name) Au lieu de la syntaxe dict (['name']), Vous pouvez utiliser namedtuple comme ceci:

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 disposez de la méthode _asdict() pour accéder à toutes les propriétés en tant que dictionnaire, mais vous ne pouvez pas ajouter des attributs supplémentaires ultérieurement, uniquement pendant la construction.

6
van

similaire à l'utilisation d'un dict, vous pouvez simplement utiliser des kwargs comme ceci:

class Person:
   def __init__(self, **kwargs):
       self.properties = kwargs

   def get_property(self, key):
       return self.properties.get(key, None)

   def main():
       timmy = Person(color = 'red')
       print(timmy.get_property('color')) #prints 'red'
1
Alex Spencer