Я искал по сети без везения. У меня есть следующий код Python:
class LED(Structure):
_fields_ = [
('color', c_char_p),
('id', c_uint32)
]
class LEDConfiguration(Structure):
_fields_ = [
('daemon_user', c_char_p),
('leds', POINTER(LED)),
('num_leds', c_uint32)
]
Вот упрощенная примерная функция, которая использует эти структуры и возвращает LEDConfiguration.
def parseLedConfiguration(path, board):
lc = LEDConfiguration()
for config in configs:
if( config.attributes['ID'].value.lstrip().rstrip() == board ):
lc.daemon_user = c_char_p('some_name')
leds = []
#Imagine this in a loop
ld = LED()
ld.color = c_char_p('red')
ld.id = int(0)
leds.append(ld)
#end imagined loop
lc.num_leds = len(leds)
lc.leds = (LED * len(leds))(*leds)
return lc
Теперь это код C, который я использую (я убрал все, что связано с настройкой python/вызовом функции parseLedConfiguration/etc, но я могу добавить его, если это будет полезно).
/*Calling the python function "parseLedConfiguration"
pValue is the returned "LEDConfiguration" python Structure*/
pValue = PyObject_CallObject(pFunc, pArgs);
Py_DECREF(pArgs);
if (pValue != NULL)
{
int i, num_leds;
PyObject *obj = PyObject_GetAttr(pValue, PyString_FromString("daemon_user"));
daemon_user = PyString_AsString(obj);
Py_DECREF(obj);
obj = PyObject_GetAttr(pValue, PyString_FromString("num_leds"));
num_leds = PyInt_AsLong(obj);
Py_DECREF(obj);
obj = PyObject_GetAttr(pValue, PyString_FromString("leds"));
PyObject_Print(obj, stdout, 0);
Моя проблема заключается в том, как получить доступ к тому, что возвращается окончательному "obj". "PyObject_Print" на "obj" показывает этот вывод:
<ConfigurationParser.LP_LED object at 0x7f678a06fcb0>
Я хочу попасть в состояние, где я могу получить доступ к этому объекту LP_LED таким же образом, как я обращаюсь к вышеуказанному объекту "LEDConfiguration".
ИЗМЕНИТЬ 1
Я думаю, что еще один важный вопрос, правильно ли мой код на Python? Так я должен хранить список или массив "Структура" внутри другой "Структуры", чтобы получить доступ к API Python C?
Благодарю!
Поскольку ваш EDIT 1 разъясняет основной вопрос, позвольте мне сказать, что сверху:
угадайте еще один, может быть, более важный вопрос, правильный ли код моего питона? Так я должен хранить список или массив "Структура" внутри другой "Структуры", чтобы получить доступ к API Python C?
Нет, это то, как вы должны хранить массив Structure
внутри другой Structure
чтобы к ней можно было получить доступ из кода, non-Python-C-API
от non-Python-C-API
. Если вы хотите получить доступ к API Python C, просто используйте list
Python.
В общем, если вы пишете код как на Python, так и на C, только одна сторона должна наклоняться назад, чтобы работать с другой. Точка использования ctypes
Structure
и POINTER
и т.п. В Python заключается в том, чтобы позволить им работать непосредственно на C, не ctypes
C API. И наоборот, точка использования таких функций, как PyList_GetItem
позволяет вам использовать обычный код Python, а не код ctypes
Python.
Итак, если вы хотите сохранить list
внутри Structure
доступ к которой можно получить через API Python C, просто сохраните list
Python - и вам действительно не нужна Structure
в первую очередь; используйте обычный класс Python (возможно, с __slots__
). Вы можете написать этот код, не импортируя ctypes
.
И наоборот, если вы хотите хранить структуры, которые можно использовать непосредственно на C, вы можете сделать это с помощью ctypes
; то, в коде C, как только вы PyObject *
в Structure
PyObject *
вам больше не нужен API Python, потому что структура - это все C. Обычно это так, как вы делаете, когда у вас есть существующий код C, и хотите взаимодействовать с ним с Python, а не когда вы разрабатываете код C с нуля, но нет правила, в котором говорится, что вы не можете использовать его другим способом.
Между тем, если это ваша первая попытка написать коды C и Python, которые говорят друг с другом, я бы предложил вам использовать Cython
. Затем, как только вам ctypes
удобно, если вы хотите изучить ctypes
, выполните другой проект, который использует Python с ctypes
чтобы поговорить с C-кодом, который ничего не знает о Python. И затем, третий проект, который использует API C, чтобы поговорить с кодом Python, который ничего не знает о ctypes
(как и большинство модулей расширения C). Как только вы знакомы со всеми тремя, вы сможете выбрать правильный вариант для большинства проектов в будущем.
Теперь, чтобы ответить на конкретную проблему:
Во-первых, когда PyList_GetItem
(или большинство других функций в API C) возвращает NULL, это означает, что существует исключение, поэтому вы должны проверить исключение и зарегистрировать его. Попытка отладить возвращаемые значения NULL в API C, не глядя на исключение набора, похоже на попытку отладки кода Python, не глядя на следы.
Во всяком случае, есть несколько очевидных причин, по которым эта функция может потерпеть неудачу: возможно, вы вызываете ее с индексом вне пределов, или, может быть, вы вызываете ее на то, что не является list
вообще.
На самом деле, второй кажется довольно очевидным здесь. Если распечатка obj
дает вам следующее:
<ConfigurationParser.LP_LED object at 0x7f678a06fcb0>
Затем у вас есть (указатель на) LED
объект, а LED
объекты не являются list
.
И если вы посмотрите на свой код, у вас, похоже, нет list
LED
объектов в любом месте, по крайней мере, в коде, который вы нам показываете. У вас есть POINTER(LED)
, который может содержать C-массив-затухающий массив C LED
, но это не то же самое, что и list
Python. Это просто массив C, который вы используете синтаксис массива C для разыменования:
PyObject *led = ledarray[i];
LP_LED
в основном является typedef дляLED *
. Другими словами, это фактическиPyObject **
. Как и в случае с любым указателем C, если он действительно указывает на массив, вы можете просто использовать его как массив; если бы это был указатель на указатель на массив, это было бы не намного сложнее; просто(*ledarray)[i]
. Какой у вас опыт работы с указателями и массивами Си?