2010-09-24 21 views
10

Tengo una estructura de tipo ctypes.Python: ¿Podemos convertir una estructura de ctypes en un diccionario?

class S1 (ctypes.Structure): 
    _fields_ = [ 
    ('A',  ctypes.c_uint16 * 10), 
    ('B',  ctypes.c_uint32), 
    ('C',  ctypes.c_uint32) ] 

si tengo X = S1(), me gustaría volver un diccionario de este objeto: Ejemplo, si hago algo como: Y = X.getdict() o Y = getdict (X) , entonces Y podría verse así:

{ 'A': [1,2,3,4,5,6,7,8,9,0], 
    'B': 56, 
    'C': 8986 } 

¿Algún ayuda?

+1

Por cierto, hay una razón por la que necesita un verdadero 'dict' objeto y no puede simplemente añadir' '__ __getitem métodos(), etc a sus clases de estructura? – llasram

+0

En mi caso, quería un dict de dicts con datos sobre procesos en un sistema ... así que tenía más sentido ponerlo en un dic de – RobotHumans

Respuesta

10

Probablemente algo como esto:

def getdict(struct): 
    return dict((field, getattr(struct, field)) for field, _ in struct._fields_) 

>>> x = S1() 
>>> getdict(x) 
{'A': <__main__.c_ushort_Array_10 object at 0x100490680>, 'C': 0L, 'B': 0L} 

Como se puede ver, se trabaja con números, pero no funciona tan bien con matrices - que tendrá que hacerse cargo de la conversión de las matrices a las listas de sí mismo. Una versión más sofisticada que intenta convertir matrices es el siguiente:

def getdict(struct): 
    result = {} 
    for field, _ in struct._fields_: 
     value = getattr(struct, field) 
     # if the type is not a primitive and it evaluates to False ... 
     if (type(value) not in [int, long, float, bool]) and not bool(value): 
      # it's a null pointer 
      value = None 
     elif hasattr(value, "_length_") and hasattr(value, "_type_"): 
      # Probably an array 
      value = list(value) 
     elif hasattr(value, "_fields_"): 
      # Probably another struct 
      value = getdict(value) 
     result[field] = value 
    return result 

Si tiene numpy y desea ser capaz de manejar matrices C multidimensionales, se debe añadir import numpy as np y el cambio:

value = list(value) 

a :

value = np.ctypeslib.as_array(value).tolist() 

Esto le dará una lista anidada.

+0

¡Agradable! Cerca de allí. Todavía estoy frente a una nueva situación en la que una estructura de tipo S1 tiene un campo que es de otro tipo S2. Me pregunto si eso también se puede convertir. –

+0

He agregado otra rama que intenta manejar estructuras anidadas (suponiendo que las estructuras puedan ser reconocidas por su atributo '_fields_'). Sin embargo, no estoy seguro si esto funciona, no lo he probado. –

+0

Lo probaré y le haré saber. Gracias. –

2

¿Qué tal algo como:

class S1(ctypes.Structure): 
    _fields_ = [ ... ] 

    def getdict(self): 
     dict((f, getattr(self, f)) for f, _ in self._fields_) 
1

propósito Un poco más general para manejar matrices dobles, y las matrices de estructuras y campos de bits.

def getdict(struct): 
    result = {} 
    #print struct 
    def get_value(value): 
     if (type(value) not in [int, long, float, bool]) and not bool(value): 
      # it's a null pointer 
      value = None 
     elif hasattr(value, "_length_") and hasattr(value, "_type_"): 
      # Probably an array 
      #print value 
      value = get_array(value) 
     elif hasattr(value, "_fields_"): 
      # Probably another struct 
      value = getdict(value) 
     return value 
    def get_array(array): 
     ar = [] 
     for value in array: 
      value = get_value(value) 
      ar.append(value) 
     return ar 
    for f in struct._fields_: 
     field = f[0] 
     value = getattr(struct, field) 
     # if the type is not a primitive and it evaluates to False ... 
     value = get_value(value) 
     result[field] = value 
    return result 
Cuestiones relacionadas