views:

97

answers:

2

Hi, I'm writing some serialization/deserialization code in Python that will read/write an inheritance hierarchy from some JSON. The exact composition will not be known until the request is sent in.

So, I deem the elegant solution to recursively introspect the Python class hierarchy to be emitted and then, on the way back up through the tree, install the correct values in a Python basic type.

E.g.,

A
|
|\
| \
B  C

If I call my "introspect" routine on B, it should return a dict that contains a mapping from all of A's variables to their values, as well as B's variables and their values.

As it now stands, I can look through B.__slots__ or B.__dict__, but I only can pull out B's variable names from there.

How do I get the __slots__/__dict__ of A, given only B? (or C).

I know that python doesn't directly support casting like C++ & its descendants do-

+2  A: 

You might try using the type.mro() method to find the method resolution order.

class A(object):
        pass

class B(A):
        pass

class C(A):
        pass

a = A()
b = B()
c = C()

>>> type.mro(type(b))
[<class '__main__.B'>, <class '__main__.A'>, <type 'object'>]
>>> type.mro(type(c))
[<class '__main__.C'>, <class '__main__.A'>, <type 'object'>]

or

>>> type(b).mro()

Edit: I was thinking you wanted to do something like this...

>>> A = type("A", (object,), {'a':'A var'})  # create class A
>>> B = type("B", (A,), {'b':'B var'})       # create class B
>>> myvar = B()

def getvars(obj):
    ''' return dict where key/value is attribute-name/class-name '''
    retval = dict()
    for i in type(obj).mro():
        for k in i.__dict__:
            if not k.startswith('_'):
                retval[k] = i.__name__
    return retval

>>> getvars(myvar)
{'a': 'A', 'b': 'B'}

>>> for i in getvars(myvar):
    print getattr(myvar, i)   # or use setattr to modify the attribute value

A Var
B Var
Ad Hoc
Hmm, that suggests I would need to upcast from one of the members of the returned list. I'm not sure how to do that in Python.
Paul Nathan
ah, I guess i didn't understand exactly what you were looking for. I attempted to clarify how I interpreted your question with an edit.
Ad Hoc
`[local_variables_of(i()) for i in type(o).mro()[:-1]]` was the solution I came up with. `local_variables_of` checks __slots__ and __dict__ and returns a list of attr names.
Paul Nathan
+1  A: 

Perhaps you could clarify what you are looking for a bit further?

At the moment your description doesn't describe Python at all. Let's assume that in your example A, B and C are the names of the classes:

class A(object) :
...     def __init__(self) :
...             self.x = 1
class B(A) :
...     def __init__(self) :
...             A.__init__(self)
...             self.y = 1

Then a runtime instance could be created as:

b = B()

If you look at the dictionary of the runtime object then it has no distinction between its own variables and variables belonging to its superclass. So for example : dir(b)

[ ... snip lots of double-underscores ... , 'x', 'y']

So the direct answer to your question is that it works like that already, but I suspect that is not very helpful to you. What does not show up is methods as they are entries in the namespace of the class, while variables are in the namespace of the object. If you want to find methods in superclasses then use the mro() call as described in the earlier reply and then look through the namespaces of the classes in the list.

While I was looking around for simpler ways to do JSON serialisation I found some interesting things in the pickle module. One suggestion is that you might want to pickle / unpickle objects rather than write your own to traverse the hieracrchy. The pickle output is an ASCII stream and it may be easier for you to convert that back and forth to JSON. There are some starting points in PEP 307.

The other suggestion is to take a look at the __reduce__ method, try it on the objects that you want to serialise as it may be what you are looking for.

Amoss
What I was working on doing is deserializing a class hierarchy with objects composed into other objects. Member objects need to be moved into a dict. This gets pushed into `json`. When I was doing analysis of the __slots__ or __dict__ variables, I saw that they do not have the parent variables. Nor do they have a pointer-to-parent.
Paul Nathan