2010-07-23 6 views
6

Escribo un código de serialización/deserialización en Python que leerá/escribirá una jerarquía de herencia de algunos JSON. La composición exacta no se conocerá hasta que se envíe la solicitud.Recorriendo recursivamente un árbol de herencia de Python en tiempo de ejecución

Por lo tanto, considero que la solución elegante para recursivamente introspectar la jerarquía de clases Python para emitir y luego, en el camino de regreso a través del árbol, instalar la correcta valores en un tipo básico de Python.

E.g., 

A 
| 
|\ 
| \ 
B C 

Si llamo a mi rutina de "introspección" en la B, debe devolver un diccionario que contiene un mapeo de todas las variables de A a sus valores, así como las variables de B y sus valores.

Tal como está ahora, puedo mirar a través de B.__slots__ o B.__dict__, pero solo puedo sacar los nombres de las variables de B de allí.

¿Cómo obtengo el __slots__/__dict__ de A, dado solo B? (o C).

sé que Python no soporta directamente la fundición como C++ & sus descendientes DO-

Respuesta

11

Usted puede intentar utilizar el método type.mro() para encontrar el orden de resolución de métodos.

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'>] 

o

>>> type(b).mro() 

Editar: Estaba pensando en lo que quería hacer algo como esto ...

>>> 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 
+0

Hmm, eso sugiere que tendría que actualizar desde uno de los miembros de la lista devuelta. No estoy seguro de cómo hacer eso en Python. –

+0

ah, supongo que no entendí exactamente lo que estabas buscando. Intenté aclarar cómo interpreté tu pregunta con una edición. –

+0

'[local_variables_of (i()) para i en tipo (o) .mro() [: - 1]]' fue la solución que se me ocurrió. 'local_variables_of' comprueba __slots__ y __dict__ y devuelve una lista de nombres attr. –

2

Tal vez podría aclarar lo que está buscando una ¿Un poco más?

Por el momento su descripción no describe Python en absoluto. Vamos a suponer que en su ejemplo A, B y C son los nombres de las clases:

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

A continuación, un ejemplo de ejecución se crearía como:

b = B() 

Si nos fijamos en el diccionario del tiempo de ejecución objeto, entonces no tiene distinción entre sus propias variables y las variables que pertenecen a su superclase. Así, por ejemplo: dir (b)

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

Así que la respuesta directa a su pregunta es que funciona como el que existe, pero sospecho que no es muy útil para usted. Lo que no aparece son los métodos, ya que son entradas en el espacio de nombres de la clase, mientras que las variables están en el espacio de nombres del objeto. Si desea buscar métodos en superclases, utilice la llamada mro() como se describe en la respuesta anterior y luego mire por los espacios de nombres de las clases en la lista.

Mientras buscaba maneras más sencillas de hacer la serialización JSON, encontré algunas cosas interesantes en el módulo Pickle. Una sugerencia es que es posible que desee desenterrar/desencofrar objetos en lugar de escribir los suyos propios para atravesar la hieracrchy. La salida de pickle es una secuencia ASCII y puede ser más fácil para usted convertirla en JSON. Hay algunos puntos de partida en PEP 307.

La otra sugerencia es echar un vistazo al método __reduce__, pruébelo en los objetos que desea serializar, ya que puede ser lo que está buscando.

+0

Lo que estaba haciendo era deserializar una jerarquía de clases con objetos compuestos en otros objetos. Los objetos miembros deben moverse a un dict. Esto se empuja en 'json'. Cuando estaba haciendo el análisis de las variables __slots__ o __dict__, vi que no tienen las variables principales. Tampoco tienen un puntero-a-padre. –

Cuestiones relacionadas