Python ctype estructuras recursivas
Pregunta
Desarrollé una DLL para un controlador en C. Escribí un programa de prueba en C ++ y la DLL funciona bien.
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 en 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 tengo una lista enlazada personalizada que contiene tipos recursivos de la siguiente manera
class EthercatDatagram(Structure):
_fields_ = [("header", EthercatDatagramHeader),
("packet_data_length", c_int),
("packet_data", c_char_p),
("work_count", c_ushort),
("next_command", EthercatDatagram)]
Esto falla, porque dentro de EthercatDatagram, EthercatDatagram no está definido, por lo que el analizador devuelve un error.
¿Cómo debo representar esta lista vinculada en Python para que mi DLL la entienda correctamente?
Solución
Es casi seguro que desea declarar next_command como puntero. Tener una estructura que se contenga a sí misma no es posible (en ningún idioma).
Creo que esto es lo que quieres:
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))]
Otros consejos
La razón por la cual
EthercatDatagram._fields_.append(("next_command", EthercatDatagram))
no funciona es que la maquinaria que crea los objetos descriptores (vea la fuente de PyCStructType_setattro
) para acceder al atributo next_command
se activa solo tras la asignación al _fields_
atributo de la clase.
Simplemente agregar el nuevo campo a la lista pasa completamente desapercibido.
Para evitar esta trampa, use 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.
Tendrá que acceder a _fields_
estáticamente después de haberlo creado.
class EthercatDatagram(Structure)
_fields_ = [...]
EthercatDatagram._fields_.append(("next_command", EthercatDatagram))