Python dictionary from an object's fields
Solution 1
Note that best practice in Python 2.7 is to use new-style classes (not needed with Python 3), i.e.
class Foo(object):
...
Also, there's a difference between an 'object' and a 'class'. To build a dictionary from an arbitrary object, it's sufficient to use __dict__
. Usually, you'll declare your methods at class level and your attributes at instance level, so __dict__
should be fine. For example:
>>> class A(object):
... def __init__(self):
... self.b = 1
... self.c = 2
... def do_nothing(self):
... pass
...
>>> a = A()
>>> a.__dict__
{'c': 2, 'b': 1}
A better approach (suggested by robert in comments) is the builtin vars
function:
>>> vars(a)
{'c': 2, 'b': 1}
Alternatively, depending on what you want to do, it might be nice to inherit from dict
. Then your class is already a dictionary, and if you want you can override getattr
and/or setattr
to call through and set the dict. For example:
class Foo(dict):
def __init__(self):
pass
def __getattr__(self, attr):
return self[attr]
# etc...
Solution 2
Instead of x.__dict__
, it's actually more pythonic to use vars(x)
.
Solution 3
The dir
builtin will give you all the object's attributes, including special methods like __str__
, __dict__
and a whole bunch of others which you probably don't want. But you can do something like:
>>> class Foo(object):
... bar = 'hello'
... baz = 'world'
...
>>> f = Foo()
>>> [name for name in dir(f) if not name.startswith('__')]
[ 'bar', 'baz' ]
>>> dict((name, getattr(f, name)) for name in dir(f) if not name.startswith('__'))
{ 'bar': 'hello', 'baz': 'world' }
So can extend this to only return data attributes and not methods, by defining your props
function like this:
import inspect
def props(obj):
pr = {}
for name in dir(obj):
value = getattr(obj, name)
if not name.startswith('__') and not inspect.ismethod(value):
pr[name] = value
return pr
Solution 4
I've settled with a combination of both answers:
dict((key, value) for key, value in f.__dict__.iteritems()
if not callable(value) and not key.startswith('__'))
Solution 5
I thought I'd take some time to show you how you can translate an object to dict via dict(obj)
.
class A(object):
d = '4'
e = '5'
f = '6'
def __init__(self):
self.a = '1'
self.b = '2'
self.c = '3'
def __iter__(self):
# first start by grabbing the Class items
iters = dict((x,y) for x,y in A.__dict__.items() if x[:2] != '__')
# then update the class items with the instance items
iters.update(self.__dict__)
# now 'yield' through the items
for x,y in iters.items():
yield x,y
a = A()
print(dict(a))
# prints "{'a': '1', 'c': '3', 'b': '2', 'e': '5', 'd': '4', 'f': '6'}"
The key section of this code is the __iter__
function.
As the comments explain, the first thing we do is grab the Class items and prevent anything that starts with '__'.
Once you've created that dict
, then you can use the update
dict function and pass in the instance __dict__
.
These will give you a complete class+instance dictionary of members. Now all that's left is to iterate over them and yield the returns.
Also, if you plan on using this a lot, you can create an @iterable
class decorator.
def iterable(cls):
def iterfn(self):
iters = dict((x,y) for x,y in cls.__dict__.items() if x[:2] != '__')
iters.update(self.__dict__)
for x,y in iters.items():
yield x,y
cls.__iter__ = iterfn
return cls
@iterable
class B(object):
d = 'd'
e = 'e'
f = 'f'
def __init__(self):
self.a = 'a'
self.b = 'b'
self.c = 'c'
b = B()
print(dict(b))
Comments
-
Julio César over 2 years
Do you know if there is a built-in function to build a dictionary from an arbitrary object? I'd like to do something like this:
>>> class Foo: ... bar = 'hello' ... baz = 'world' ... >>> f = Foo() >>> props(f) { 'bar' : 'hello', 'baz' : 'world' }
NOTE: It should not include methods. Only fields.
-
Julio César over 15 yearsThis code includes methods. Is there a way to exclude methods? I only need the object's fields. Thanks
-
dF. over 15 yearsThat works also, but be aware that it will only give you the attributes set on the instance, not on the class (like class Foo in your example)...
-
quamrana over 15 yearsSo, jcarrascal, you are better off wrapping the above code in a function like props(), then you can call either props(f) or props(Foo). Notice that you are almost always better off writing a function, rather than writing 'inline' code.
-
zakdances about 11 yearsWhat happens if one of A's attribute's has a custom getter? (a function with a @property decorator)? Does it still show up in ____dict____? What will its value be?
-
Antimony almost 11 years
__dict__
won't work if the object is using slots (or defined in a C module). -
chiffa over 10 yearsIs there an equivalent of this method for the class objects? I.E. Instead of using f=Foo() and then doing f.__dict__, do directly Foo.__dict__?
-
Ehtesh Choudhury over 10 years
ismethod
doesn't catch functions. Example:inspect.ismethod(str.upper)
.inspect.isfunction
isn't much more helpful, though. Not sure how to approach this right away. -
robert over 9 yearsSorry, I'm coming to this late, but shouldn't
vars(a)
do this? For me it's preferable to invoking the__dict__
directly. -
Tadhg McDonald-Jensen over 8 yearsfor second example it would be better to do
__getattr__ = dict.__getitem__
to exactly replicate the behaviour, then you would also want__setattr__ = dict.__setitem__
and__delattr__ = dict.__delitem__
for complete-ness. -
ThorSummoner almost 8 yearsI made some tweaks to crudely recurs and ignore all errors to a depth here, thanks! gist.github.com/thorsummoner/bf0142fd24974a0ced778768a33a3069
-
tvt173 about 7 yearsAgreed. Note that you can also convert the other way (dict->class) by typing
MyClass(**my_dict)
, assuming you have defined a constructor with parameters that mirror the class attributes. No need to access private attributes or override dict. -
cowbert over 6 yearsThe best practice in Python 2.7 is to use
vars(Object)
ifObject
inherits fromobject
-
maxkoryukov over 6 yearsAfter this answer still not clear how to get a dictionary from an object. Not properties, but entire dictionary;)
-
maxkoryukov over 6 years@robert since it is the end of 2017 (9 years after the question was asked, and this answer was accepted), so I have moved your notice about
vars
to the answer's body. -
Naramsim almost 6 yearsAny way to preserve the order of the keys?
-
Jacob Lee over 5 yearsIt may be worth including a warning that vars(obj) and obj.__dict__ will not provide custom class attributes (e.g. class Foo(): fooname='fooname'). Some might not expect that, since obj.class_attribute and obj.object_attribute look like similar.
-
Hugh W over 5 yearsCan you explain why it's more Pythonic?
-
Berislav Lopac over 5 yearsFirst, Python generally shuns callings dunder items directly, and there is almost always a method or function (or operator) to access it indirectly. In general, dunder attributes and methods are an implementation detail, and using the "wrapper" function allows you to separate the two. Second, this way you can override the
vars
function and introduce additional functionality without changing the object itself. -
Berislav Lopac over 5 years
__dict__
is an attribute, not a method, so this example changes the interface (i.e. you need to call it as a callable), so it's not overriding it. -
should_be_working about 5 yearsIn this case what's the solution ? Since
vars()
doesn't work -
Albert almost 5 years@should_be_working
dir
is the solution in this case. See the other answer about that. -
c z over 4 yearsIt still fails if your class uses
__slots__
though. -
Berislav Lopac over 4 yearsThat is correct, and I always felt that it would be a good direction to extend
vars
to, i.e. to return an equivalent of__dict__
for "slotted" classes. For now, it can be emulated by adding a__dict__
property which returns{x: getattr(self, x) for x in self.__slots__}
(not sure whether that affects the performance or behaviour in any way though). -
mrgloom over 4 yearsWhat is the difference between
vars
and__dict__
? -
Morten over 4 yearsNice, btw note this is for python2.7, for python3 relpace iteritems() with simply items().
-
Alex over 4 yearsThis will grab also all the methods, but we need only class+instance fields. Maybe
dict((x, y) for x, y in KpiRow.__dict__.items() if x[:2] != '__' and not callable(y))
will solve it? But there still could bestatic
methods :( -
Alex over 4 yearsAnd what about
staticmethod
? It's notcallable
. -
Anakhand over 3 yearsAgree with @cz ; and +1 to Berislav for extending
vars
to work with__slots__
(and even objects that don't have neither__dict__
nor__slots__
). For now, I have written a wrapper function to deal with this in an answer below; I'd say it's better to add this functionality externally rather than require your object to define a__dict__
property (which might not be possible). -
Zack Plauché almost 3 years
vars
does not return class attributes, only instance attributes (set by__init__
)