2009-08-04 10 views
8

He desarrollado una DLL para un controlador en C. Escribí un programa de prueba en C++ y la DLL funciona bien.python ctype recursive structures

Ahora me gustaría interactuar con esta DLL usando Python. He ocultado con éxito la mayoría de las estructuras C definidas por el usuario, pero hay un punto en el que tengo que usar estructuras C. Soy bastante nuevo para Python, así que puedo equivocarme.

Mi enfoque es redefinir algunas estructuras en python usando ctype y luego pasar la variable a mi DLL. Sin embargo, en estas clases que tengo una lista enlazada costumbre que contiene tipos recursivos como sigue

class EthercatDatagram(Structure): 
    _fields_ = [("header", EthercatDatagramHeader), 
       ("packet_data_length", c_int), 
       ("packet_data", c_char_p), 
       ("work_count", c_ushort), 
       ("next_command", EthercatDatagram)] 

Esta falla, porque EthercatDatagram dentro, EthercatDatagram no está ya definido por lo que el analizador devuelve un error.

¿Cómo debo representar esta lista vinculada en python para que mi DLL lo entienda correctamente?

Respuesta

15

Es casi seguro que desee declarar next_command como un puntero. Tener una estructura que se contiene a sí misma no es posible (en ningún idioma).

Creo que esto es lo que quiere:

class EthercatDatagram(Structure): 
    pass 
EthercatDatagram._fields_ = [ 
    ("header", EthercatDatagramHeader), 
    ("packet_data_length", c_int), 
    ("packet_data", c_char_p), 
    ("work_count", c_ushort), 
    ("next_command", POINTER(EthercatDatagram))] 
+1

"no es posible (en ningún idioma)": eso es cierto acerca de las clases o estructuras de estilo c/C++/java, pero en los lenguajes con tipos de datos algebraicos no solo es posible sino que también es muy común. p.ej. 'data List a = Cons a (Lista a) | Nil' en los idiomas de la familia ML (ocaml/haskell/SML/etc). – sinelaw

-1

Deberá tener acceso a _fields_ estáticamente después de haberlo creado.

class EthercatDatagram(Structure) 
    _fields_ = [...] 

EthercatDatagram._fields_.append(("next_command", EthercatDatagram)) 
+1

Esto no funciona. Se compila y ejecuta, pero tratar de usar realmente una instancia de la clase da un error: AttributeError: el objeto 'EthercatDatagram' no tiene ningún atributo 'next_command' – user9876

+0

La respuesta correcta está debajo, según lo publicado por el usuario9876 Primero debe declarar la clase con 'pase', luego declare los campos en una segunda llamada. Piense en ello como una declaración avanzada. – bpescatore

0

La razón por la

EthercatDatagram._fields_.append(("next_command", EthercatDatagram)) 

que no funciona es que la maquinaria que crea los objetos de descriptor (vea la fuente de la función PyCStructType_setattro) para acceder al atributo next_command se activa solo en la asignación al atributo _fields_ de la clase. El solo hecho de agregar el nuevo campo a la lista pasa completamente desapercibido.

Para evitar este riesgo, utilice siempre una tupla (y no una lista) como el valor del atributo _fields_: eso dejará en claro que debe asignar un nuevo valor al atributo y no modificarlo en su lugar.