Getting a dictionary from an object

B

Bruno Desthuilliers

Steven D'Aprano a écrit :
If I have understood you, you have some object like such:

obj.foo = 1
obj.bar = 2
obj.spam = 'a'
obj.eggs = 'b'

say.

You want to use it something like this:

print "My object has fields %(foo)s; %(bar)s; %(spam)s; %(eggs)s." % obj

except that doesn't work. So I would simply change the reference to obj to
obj.__dict__ and it should do exactly what you want.

Nope, it doesn't work with computed attributes (properties, descriptors,
....).

The most obvious solution is the decorator pattern - which is somewhat
the op was trying to do.

Another solution is to dynamically add a __getitem__ method to obj
before using'em that way, either by setting explicitly the method as an
attribute of the object's class or by using the import_with_metaclass()
trick from David Mertz.

(snip)
It really does help to explain what your functional requirements are,
instead of focusing on one, possibly pointless, implementation.
+1 on this !-)
 
B

Bruno Desthuilliers

Steven D'Aprano a écrit :
(snip)
> I don't think you are correct. As far as I can see, properties do have
an entry in obj.__dict__ the same as other attributes, although there is
certainly some strangeness going on with properties.

Using the sample code from here:
http://www.python.org/2.2.3/descrintro.html#property

class C(object):
def __init__(self):
self.__x = 0
def getx(self):
return self.__x
def setx(self, x):
if x < 0: x = 0
self.__x = x
x = property(getx, setx)

I see _C__x in C().__dict__, exactly as expected. (snip)

Yes, but you don't see 'x'. Poking into the object's __dict__ would
defeat the whole point of computed attributes - which by the way need
not directly map to a protected or private variable, nor even be
properties (think: descriptors).
I can't see any way to inspect a Python object and get a list of
properties,

I do :

def list_properties(obj):
proptype = type(property()) # not defined in types
klass = obj.__class__
names = dir(klass) # so we get inherited attribs as well
d = dict([(name, getattr(klass, name)) for name in names])
return [name for name, attrib in d.items() \
if type(attrib) is proptype]



Note that this won't find all descriptors (I've tried and it really
harder... there are a lot of things in a class.__dict__ that have a
__get__() method, most of'em not defined in the types module).

Anyway, you won't need it... (I mean, the OP don't need it to solve it's
problem)
so you might have to keep your own list: add a class-attribute
of your object which keeps a list of all the properties:

class Obj:
# various methods, attributes and properties
...
# keep a list of special properties that don't show
# up correctly in __dict__
special = ['foo', 'bar']

# now define a special method that makes a copy of
# __dict__ and adds special properties to it

def objdict(self):
D = self.__dict__.copy()
# assume shallow copy is enough
for property_name in self.special:
D[property_name] = self.__getattribute__(property_name)
return D

then call it when you need it:

print "My object has fields %(foo)s and %(bar)s." % obj.objdict()

This means adding responsabilities to the class when the need is
obviously orthogonal to the class's responsabilities. Implementing a
generic decorator pattern in Python does'nt require more code, doesn't
requires the class nor the object to be modified at all, is probably
more robust, and is, well... more generic !-) (should I say 'more
pythonic' ?)
It would be nice to see an easier way to introspect objects and get
a list of properties.

You're dream is now reality. Now ain't *that* nice ?-)

Bruno
 
D

Dennis Lee Bieber

BTW, parts of this thread should remind us all that it's usually better
to clearly describe the *problem* before asking for comments on the
solution...
</meta>

"""I would like to have a quick way to create dicts from object, so
that a call to foo['bar'] would return obj.bar."""

Actually this is the problem, (I never said anything about _assigning_
new keys in foo), and the line following it is my question ;)
No... That is a description of a proposed/desired implementation
with no real Use-Case... If you'd shown something similar to a print
statement with an explanation

print "%(this)s or %(that)" % obj
#desire obj to behave as a dict for this type of print

you'd likely have gotten much faster or more applicable responses.

--
 
S

Steven Bethard

Thanos said:
I didn't know about it, but I knew about object.__dict__ which is, as I
see equivalent with vars(object). But it doesn't do the job for me,
since it fails to grab all obj.foo's, some of them being properties,
etc.

How about something like:
dict((name, getattr(obj, name)) for name in dir(obj))

For example:

py> class C(object):
.... x = 1
.... @property
.... def y(self):
.... return 2
.... def __init__(self):
.... self.z = 3
....
py> c = C()
py> d = dict((name, getattr(c, name)) for name in dir(c))
py> d['x']
1
py> d['y']
2
py> d['z']
3

Looks like this will get instance attributes, class attributes and
properties just fine.

STeVe
 
D

Dark Cowherd

voiceless-ly'rs
What does this mean?? Just curious (googled that and ly'rs and didnt
find anything relevant)
 
J

John Machin

Dark said:
What does this mean?? Just curious (googled that and ly'rs and didnt
find anything relevant)

The voiceless part I understand to mean that Bruno is "shocked and
stunned and not a little bit amazed" [1] at Steven's masterstroke which
came out of the blue and trumped all previous efforts -- a true "deus ex
machina", a thunderbolt from Olympus -- or if you want a one-word
colloquialism, he's gobsmacked.

The -ly'rs part means that in his shocked state he has tried to emulate
the timbot's characteristic sign-off [2], but failed to get the syntax
correct.

[1] Billy Connolly
[2] http://www.python.org/tim_one/ ... or just check out a few postings
by Tim Peters in this newsgroup.
 
B

bruno modulix

s/ly'rs/ly y'rs/
The voiceless part I understand to mean that Bruno is "shocked and
stunned and not a little bit amazed" [1] at Steven's masterstroke which
came out of the blue and trumped all previous efforts -- a true "deus ex
machina", a thunderbolt from Olympus -- or if you want a one-word
colloquialism, he's gobsmacked.

The -ly'rs part means that in his shocked state he has tried to emulate
the timbot's characteristic sign-off [2], but failed to get the syntax
correct.

one-hundred-percent-correct-ly y'rs !-)
 
T

Thanos Tsouanas

How about something like:
dict((name, getattr(obj, name)) for name in dir(obj))
Pretty!!!

Looks like this will get instance attributes, class attributes and
properties just fine.

But not SQLObject's objects...
Any idea why? (Getting attribute errors, it seems that these
"attributoids" are not listed in dir(obj), so i have to use my ugly
dictobj class.. :(
 
S

Steven Bethard

Thanos said:
But not SQLObject's objects...
Any idea why? (Getting attribute errors, it seems that these
"attributoids" are not listed in dir(obj), so i have to use my ugly
dictobj class.. :(

I don't know how SQLObjects are implemented, but I'm guessing they use
__getattr__ or __getattribute__:

py> class C(object):
.... w = 1
.... @property
.... def x(self):
.... return 2
.... def __init__(self):
.... self.y = 3
.... def __getattr__(self, name):
.... if name == 'z':
.... return 4
....
py> c = C()
py> d = dict((name, getattr(c, name)) for name in dir(c))
py> d['w'], d['x'], d['y']
(1, 2, 3)
py> d['z']
Traceback (most recent call last):
File "<interactive input>", line 1, in ?
KeyError: 'z'

Any attribute simulated through __getattr__ or __getattribute__ cannot
be found by dir():

py> dir(c)
['__class__', '__delattr__', '__dict__', '__doc__', '__getattr__',
'__getattribute__', '__hash__', '__init__', '__module__', '__new__',
'__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__str__',
'__weakref__', 'w', 'x', 'y']

For this reason, I try to avoid implementing attributes through these
methods, but sometimes it's unavoidable.

STeVe
 
M

Mike Moum

Thanos Tsouanas wrote:

I'm not sure what you're getting at, but have you tried this:

class A(object):
def __getitem__(self, ky):
return self.__dict__[ky]

for example: def __init__(self,a,b,c):
self.a = a
self.b = b
self.c = c
def __getitem__(self, ky):
return self.__dict__[ky]

>>> a = A(1,2,3)
>>> a['a'] 1
>>> a['b'] 2
>>>
Hello.

I would like to have a quick way to create dicts from object, so that a
call to foo['bar'] would return obj.bar.

The following works, but I would prefer to use a built-in way if one
exists. Is there one?

Thanks in advance.

class dictobj(dict):
"""
class dictobj(dict):
A dictionary d with an object attached to it,
which treats d['foo'] as d.obj.foo.
"""
def __init__(self, obj):
self.obj = obj
def __getitem__(self, key):
return self.obj.__getattribute__(key)
 
M

Mike Moum

Thanos Tsouanas wrote:

I'm not sure what you're getting at, but have you tried this:

class A(object):
def __getitem__(self, ky):
return self.__dict__[ky]

for example: def __init__(self,a,b,c):
self.a = a
self.b = b
self.c = c
def __getitem__(self, ky):
return self.__dict__[ky]

>>> a = A(1,2,3)
>>> a['a'] 1
>>> a['b'] 2
>>>
Hello.

I would like to have a quick way to create dicts from object, so that a
call to foo['bar'] would return obj.bar.

The following works, but I would prefer to use a built-in way if one
exists. Is there one?

Thanks in advance.

class dictobj(dict):
"""
class dictobj(dict):
A dictionary d with an object attached to it,
which treats d['foo'] as d.obj.foo.
"""
def __init__(self, obj):
self.obj = obj
def __getitem__(self, key):
return self.obj.__getattribute__(key)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,982
Messages
2,570,186
Members
46,744
Latest member
CortneyMcK

Latest Threads

Top