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
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)
Définir des attributs de cette manière n'est certainement pas la meilleure façon de résoudre un problème. Non plus:
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
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.
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
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)
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)
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.
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'