Getting a dictionary from an object

T

Thanos Tsouanas

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)
 
B

Bruno Desthuilliers

Thanos Tsouanas a écrit :
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)

I'd replace this last line with:
return getattr(self.obj, key)


Now given your specs, I don't see what's wrong with your solution.
 
T

Thanos Tsouanas

Thanos Tsouanas a écrit :
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)

I'd replace this last line with:
return getattr(self.obj, key)

Now given your specs, I don't see what's wrong with your solution.

I just dont want to use my class, if one already exists in the
libraries (or any other way to achieve the same thing), that's all ;)

Thanks for the tip.
 
S

Steven D'Aprano

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.

That looks rather confusing to me. Why not just call obj.bar, since it
doesn't look like you are actually using the dictionary at all?
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)

I don't think this is particularly useful behaviour. How do you use it?

py> D = dictobj("hello world")
py> D
{}
py> D.obj
'hello world'
py> D["food"] = "spam"
py> D
{'food': 'spam'}
py> D["food"]
Traceback (most recent call last):
File "<stdin>", line 1, in ?
File "<stdin>", line 5, in __getitem__
AttributeError: 'str' object has no attribute 'food'
 
M

Mike Meyer

Steven D'Aprano said:
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.

That looks rather confusing to me. Why not just call obj.bar, since it
doesn't look like you are actually using the dictionary at all?

Well, I needed exactly this functionality last week. I have a
collection of (rather messy) classes that have a slew of attributes as
values. I would have used a dictionary for this, but I didn't write
the code.

I have to be able to display these objects (in HTML, if it matters),
and have as a requirement that the format string live in a database.

My solution didn't look to different from dictobj. There's some extra
mechanism to fetch the format string from the database, and some
formatting of the attribute based on meta-information in the object,
but it's the same basic idea.
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)

I don't think this is particularly useful behaviour. How do you use it?

def __str__(self):
return self._format % self


<mike
 
T

Thanos Tsouanas

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.

That looks rather confusing to me. Why not just call obj.bar, since it
doesn't look like you are actually using the dictionary at all?

I don't think this is particularly useful behaviour. How do you use it?

print foo %do

where do is a dictobj object...
 
S

Steven Bethard

Thanos said:
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?

Maybe I'm not understanding your problem, but have you looked at the
builtin "vars()"?

STeVe
 
S

Steven D'Aprano

def __str__(self):
return self._format % self

That doesn't work. It calls self.__str__ recursively until Python halts
the process.
.... _format = "Thing %s is good."
.... def __str__(self):
.... return self._format % self
.... File "<stdin>", line 4, in __str__
File "<stdin>", line 4, in __str__
...
File "<stdin>", line 4, in __str__
File "<stdin>", line 4, in __str__
RuntimeError: maximum recursion depth exceeded
 
S

Steven D'Aprano

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.

That looks rather confusing to me. Why not just call obj.bar, since it
doesn't look like you are actually using the dictionary at all?

I don't think this is particularly useful behaviour. How do you use it?

print foo %do

where do is a dictobj object...

Are you telling me that the ONLY thing you use dictobj objects for is to
print them?

I don't think so. I do know how to print an object, amazingly.

Perhaps you would like to explain how you use the rest of the
functionality of the dictobj, instead of taking my words out of context
and giving an inane answer.

Why jump through all those hoops to get attributes when Python already
provides indexing and attribute grabbing machinery that work well? Why do
you bother to subclass dict, only to mangle the dict __getitem__ method so
that you can no longer retrieve items from the dict?
 
T

Thanos Tsouanas

Are you telling me that the ONLY thing you use dictobj objects for is to
print them?

I'm sorry to disappoint you, but yes. When you have a long text
template to fill-out, with lots of %(foo)s, and all those foos are
attributes of an object, it really helps to have dictobj.
I don't think so. I do know how to print an object, amazingly.

Please, tell me, how would you print it in my case?
Perhaps you would like to explain how you use the rest of the
functionality of the dictobj, instead of taking my words out of context
and giving an inane answer.

I dont see _ANY_ other functionality in the dictobj class. Do you?
Why jump through all those hoops to get attributes when Python already
provides indexing and attribute grabbing machinery that work well? Why do
you bother to subclass dict, only to mangle the dict __getitem__ method so
that you can no longer retrieve items from the dict?

Because *obviously* I don't know of these indexing and attribute
grabbing machineries you are talking about in my case. If you cared to
read my first post, all I asked was for the "normal", "built-in" way to
do it. Now, is there one, or not?
 
T

Thanos Tsouanas

Thanos said:
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?

Maybe I'm not understanding your problem, but have you looked at the
builtin "vars()"?

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.

vars() is good to know though, Thanks!
 
T

Thanos Tsouanas

Thanos Tsouanas a écrit :

If you re-read your first post, you'll notice that you didn't say
anything about the intention, only about implementation !-)

"""The following works, but I would prefer to use a built-in way if one
exists. Is there one?"""
Now if your *only* need is to access object as a dict for formated
output, you don't need to subclass dict. This is (well, should be) enough:

class Wrapper(object):
def __init__(self, obj):
self._obj = obj
def __getitem__(self, name):
return getattr(self._obj, name)

This works with 'normal' attributes as well as with properties. Notice
that this wrapper is read-only, and don't pretend to be a real
dictionnary - but still it implements the minimum required interface for
"%(attname)s" like formatting.

Thanks!! You made clear what 'the extra functionality' was. Indeed
there is no need to subclass dict...

it does!
 
B

Bruno Desthuilliers

Thanos Tsouanas a écrit :
On Sun, Jul 24, 2005 at 01:43:43PM +1000, Steven D'Aprano wrote:
(snip)
Because *obviously* I don't know of these indexing and attribute
grabbing machineries you are talking about in my case. If you cared to
read my first post, all I asked was for the "normal", "built-in" way to
do it. Now, is there one, or not?

If you re-read your first post, you'll notice that you didn't say
anything about the intention, only about implementation !-)

Now if your *only* need is to access object as a dict for formated
output, you don't need to subclass dict. This is (well, should be) enough:

class Wrapper(object):
def __init__(self, obj):
self._obj = obj
def __getitem__(self, name):
return getattr(self._obj, name)

This works with 'normal' attributes as well as with properties. Notice
that this wrapper is read-only, and don't pretend to be a real
dictionnary - but still it implements the minimum required interface for
"%(attname)s" like formatting.

HTH
Bruno
 
B

Bruno Desthuilliers

Bruno Desthuilliers a écrit :
(snip)
class Wrapper(object):
def __init__(self, obj):
self._obj = obj
def __getitem__(self, name):
return getattr(self._obj, name)

If you want the Wrapper to be more like a Decorator (ie still can use
the Wrapper object as if it was the wrapped object), you can add this:

def __getattr__(self, name):
return getattr(self._obj, name)

def __setattr__(self, name, val):
if name == '_obj':
super(Wrapper, self).__setattr__(name, val)
else:
setattr(self._obj, name, val)

The Python cookbook may have some receipes too for this kind of funny
things...
 
T

Thanos Tsouanas

I gave you a solution based on the Decorator pattern in another post,
but there is also the possibility to add a __getitem__ method directly
to the to-be-formatted object's class:

def mygetitem(obj, name):
return getattr(obj, name)

setattr(obj.__class__, '__getitem__', mygetitem)
obj['bar']

I used what you suggested earlier with the Wrapper, without subclassing
dict anymore. Thanks!
<meta>
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 ;)

Thanks again!
 
B

Bruno Desthuilliers

Steven D'Aprano a écrit :
On Sun, 24 Jul 2005 02:09:54 +0300, Thanos Tsouanas wrote:

(snip)

Are you telling me that the ONLY thing you use dictobj objects for is to
print them?

I don't think so. I do know how to print an object, amazingly.

Perhaps you would like to explain how you use the rest of the
functionality of the dictobj, instead of taking my words out of context
and giving an inane answer.

Why jump through all those hoops to get attributes when Python already
provides indexing and attribute grabbing machinery that work well? Why do
you bother to subclass dict, only to mangle the dict __getitem__ method so
that you can no longer retrieve items from the dict?

The idea of the OP is not to use the dictobj as a full fledged dict,
just to wrap the obj in something that is dict-like enough to be used
for "%(attname)s" formatting. I also assume that he doesn't want to
manually alter the code of each and every class to achieve this !-)

So we can certainly agree that subclassing dict here is overkill and a
bit misleading, but there are probably better ways to express this
feeling. Of course, it would have been simpler if the OP had tell us
from the start what was it's use case, but what...

One could of course use metaclass tricks and the like to customize the
objects __str__ or __repr__ (as in David Mertz's gnosis.magic package),
but that would be overkill too IMHO.

The plain old Decorator[1] pattern is probably enough in this case,
since it's quite easy to implement a generic Decorator in Python.
Another solution could be to dynamically modify the to-be-wrapped
object's class to add a __getitem__ method.
 
B

Bruno Desthuilliers

Thanos Tsouanas a écrit :
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.
(snip)

print foo %do

where do is a dictobj object...

I gave you a solution based on the Decorator pattern in another post,
but there is also the possibility to add a __getitem__ method directly
to the to-be-formatted object's class:

def mygetitem(obj, name):
return getattr(obj, name)

setattr(obj.__class__, '__getitem__', mygetitem)
obj['bar']


<meta>
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>

My 2 cents...
Bruno
 
B

Bruno Desthuilliers

Thanos Tsouanas a écrit :
On Sun, Jul 24, 2005 at 02:01:30PM +0200, Bruno Desthuilliers wrote:
(snip)

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

This is about the " how", not about the "why". The "why" is:
fmt_string % dictobj

BTW, there are many templating solutions in Python, that are heavier but
may (or may not, depending on the context) scale better or be more
usable than string formatting...

Bruno
 
S

Steven D'Aprano

I'm sorry to disappoint you, but yes. When you have a long text
template to fill-out, with lots of %(foo)s, and all those foos are
attributes of an object, it really helps to have dictobj.

Ah, now we're making progress in finding out what the purpose of the
dictobj is! Thank you, this is starting to become clearer now.
Please, tell me, how would you print it in my case?

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.

Does that help?

[snip]
Because *obviously* I don't know of these indexing and attribute
grabbing machineries you are talking about in my case. If you cared to
read my first post, all I asked was for the "normal", "built-in" way to
do it. Now, is there one, or not?

I did read your first post. Unfortunately, you had not explained what you
were trying to do very well. Your initial solution involved sub-classing
dict. I made the fatal mistake of trying to guess what you needed from
your sample code -- a natural mistake to make, given how vague your
requirements were. Or rather, non-existent.

It really does help to explain what your functional requirements are,
instead of focusing on one, possibly pointless, implementation.

If I have understood your functional requirements correctly, you don't
need "to have a quick way to create dicts from object, so that a call to
foo['bar'] would return obj.bar" at all.
 
S

Steven D'Aprano

Thanos said:
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?

Maybe I'm not understanding your problem, but have you looked at the
builtin "vars()"?

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.

You could have mentioned this earlier.

But 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. (The _C is Python's
standard name mangling of "semi-private" attributes starting with double
underscores.)

I can't see any way to inspect a Python object and get a list of
properties, 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()


It would be nice to see an easier way to introspect objects and get
a list of properties.
 

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

No members online now.

Forum statistics

Threads
473,982
Messages
2,570,185
Members
46,738
Latest member
JinaMacvit

Latest Threads

Top