Вопрос по python, recursion, structure, dll, ctypes – рекурсивные структуры python ctype

8

Я разработал DLL для драйвера на C. Я написал тестовую программу на C ++, и DLL работает нормально.

Теперь я хотел бы взаимодействовать с этой DLL с помощью Python. Я успешно скрыл большинство пользовательских С-структур, но есть один момент, когда мне нужно использовать С-структуры. Я довольно плохо знаком с Python, поэтому могу ошибаться.

Мой подход заключается в том, чтобы переопределить несколько структур в python с использованием ctype, а затем передать переменную в мою DLL. Однако в этом классе у меня есть собственный связанный список, который содержит рекурсивные типы, как следует

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

Это терпит неудачу, потому что внутри EthercatDatagram, EthercatDatagram еще не определен, поэтому анализатор возвращает ошибку.

Как мне представить этот связанный список в python, чтобы моя DLL понимала его правильно?

Ваш Ответ

3   ответа
15

Вы почти наверняка захотите объявить next_command в качестве указателя. Наличие структуры, которая содержит себя, невозможно (на любом языке).

Я думаю, что это то, что вы хотите:

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))]
"невозможно" (на любом языке) " - это верно для структур или классов в стиле c / c ++ / java, но в языках с алгебраическими типами данных это не только возможно, но и очень распространено. напримерdata List a = Cons a (List a) | Nil на языках семейства ML (ocaml / haskell / SML / и т. д.).
-1

Вам нужно будет получить доступ_fields_ статически после того, как вы его создали.

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

EthercatDatagram._fields_.append(("next_command", EthercatDatagram))
Ниже приведен правильный ответ, опубликованный пользователем9876. Сначала необходимо объявить класс с помощью «pass», а затем объявить поля во втором вызове. Думайте об этом как о предварительной декларации.
Это не работает. Он компилируется и запускается, но попытка фактически использовать экземпляр класса выдает ошибку: AttributeError: & apos; EthercatDatagram & apos; У объекта нет атрибута "next_command"
0

Причина по которой

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

не работает, это то, что механизм, который создает объекты дескриптора (см. источникPyCStructType_setattro функция) для доступа кnext_command атрибут активированonly upon assignment к_fields_ атрибут класса. Простое добавление нового поля в список совершенно незаметно.

Чтобы избежать этой ловушки, всегда используйте кортеж (а не список) в качестве значения_fields_ Атрибут: это прояснит, что вы должны назначить новое значение атрибуту, а не изменять его на месте.

Похожие вопросы