views:

6125

answers:

6

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.

Thanks

+15  A: 

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
dF
This code includes methods. Is there a way to exclude methods? I only need the object's fields. Thanks
Julio César
A: 

Is there a way to exclude methods from the solution posted above?

Julio César
+4  A: 

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('__'))
Julio César
That 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)...
dF
So, 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.
quamrana
A: 

The "if not callable(...)" filter does exclude methods.

Nicholas Riley
+8  A: 

Note that best practice in current versions of Python is to use new-style classes, 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}

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...
+1 Your first suggestion just helped me out. Thanks.
tarn
+2  A: 

To build a dictionary from an arbitrary object, it's sufficient to use dict.

This misses attributes that the object inherits from its class. For example,

class c(object):
    x = 3
a = c()

hasattr(a, 'x') is true, but 'x' does not appear in a.__dict__

indentation