Is it possible to create an object from a dictionary in python in such a way that each key is an attribute of that object?
Something like this:
d = { 'name': 'Oscar', 'lastName': 'Reyes', 'age':32 }
e = Employee(d)
print e.name # Oscar
print e.age + 10 # 42
I think it would be pretty much the inverse of this question: Python dictionary from an object's fields
Sure, something like this:
class Employee(object):
def __init__(self, initial_data):
for key in initial_data:
setattr(self, key, initial_data[key])
Update
As Brent Nash suggests, you can make this more flexible by allowing keyword arguments as well:
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])
Then you can call it like this:
e = Employee({"name": "abc", "age": 32})
or like this:
e = Employee(name="abc", age=32)
or even like this:
employee_template = {"role": "minion"}
e = Employee(employee_template, name="abc", age=32)
def __init__(self,**initial_data)
you get the added benefit of having an init method that can also do keyword arguments too (e.g. "e = Employee(name='Oscar')" or just take in a dictionary (e.g. "e = Employee(**dict)"). - Brent Writes CodeEmployee(some_dict)
and the Employee(**some_dict)
APIs is inconsistent. Whichever is better should be supplied. - Mike Graham()
instead of None
, you could do it like so: def __init__(self, iterable=(), **kwargs): self.__dict__.update(iterable, **kwargs)
. - Matt Anderson[[setattr(self,key,d[key]) for key in d] for d in some_dict]
- T.Z.AddressNotFoundError
's (to return corrected data in that case, rather than blowing up) - I found it crazy that something so easy in PHP ((object) ['x' => 'y']
) required so much cruft in Python - Someguy123
Setting attributes in this way is almost certainly not the best way to solve a problem. Either:
You know what all the fields should be ahead of time. In that case, you can set all the attributes explicitly. This would look like
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
or
You don't know what all the fields should be ahead of time. In this case, you should store the data as a dict instead of polluting an objects namespace. Attributes are for static access. This case would look like
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
Another solution that is basically equivalent to case 1 is to use a collections.namedtuple
. See van's answer for how to implement that.
You can access the attributes of an object with __dict__
, and call the update method on it:
>>> 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
__dict__
is an implementation artifact and should not be used. Also, this ignores the existence of descriptors on the class. - Ignacio Vazquez-Abrams__dict__
is a documented part of the language, not an implementation artifact. - Dave Kirbysetattr
is preferable to accessing __dict__
directly. You have to keep in mind a lot of things that could lead to __dict__
not being there or not doing what you want it to when you use __dict__
, but setattr
is virtually identical to actually doing foo.bar = baz
. - Mike Graham
I think that answer using settattr
are the way to go if you really need to support dict
.
But if Employee
object is just a structure which you can access with dot syntax (.name
) instead of dict syntax (['name']
), you can use namedtuple like this:
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'}
You do have _asdict()
method to access all properties as dictionary, but you cannot add additional attributes later, only during the construction.
property
. - Mike Graham
Why not just use attribute names as keys to a dictionary?
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
You can initialize with named arguments, a list of tuples, or a dictionary, or individual attribute assignments, e.g.:
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)
Alternatively, instead of raising the attribute error, you can return None for unknown values. (A trick used in the web2py storage class)
say for example
class A():
def __init__(self):
self.x=7
self.y=8
self.z="name"
if you want to set the attributes at once
d = {'x':100,'y':300,'z':"blah"}
a = A()
a.__dict__.update(d)
a.__dict__.update(x=100, y=300, z="blah")
- simno
similar to using a dict, you could just use kwargs like so:
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'
dict
is not a great name for variable, it hides the typedict
- van