1

我一直在网上搜索没有运气。我有以下 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”函数/等有关的所有内容,但如果有帮助,我可以添加它)。

        /*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”的内容。“obj”上的“PyObject_Print”显示以下输出:

<ConfigurationParser.LP_LED object at 0x7f678a06fcb0>

我想进入一种可以访问该 LP_LED 对象的状态,就像我访问上面的“LEDConfiguration”对象一样。

编辑 1

我想另一个可能更重要的问题是,我的 python 代码是否正确?那是我应该如何将“结构”列表或数组存储在另一个“结构”中,以便可以从 Python C API 访问它?

谢谢!

4

1 回答 1

1

由于您的 EDIT 1 澄清了基本问题,让我把它放在首位:

猜猜另一个可能更重要的问题,我的 python 代码是否正确?那是我应该如何将“结构”列表或数组存储在另一个“结构”中,以便可以从 Python C API 访问它?

不,这就是你应该如何Structure在另一个数组中存储一个数组,Structure以便可以从non-Python-C-APIC 代码访问它。如果您希望从 Python C API 访问它,只需使用 Python list.

一般来说,如果你同时用 Python 和 C 编写代码,只有一侧必须向后弯曲才能与另一侧一起工作。在 Python中使用ctypes Structures 和POINTERs 之类的点是让它们可以直接在 C 中工作,而不必经过 C API。相反,使用类似函数的PyList_GetItem目的是允许您使用普通的 Python 代码,而不是ctypesPython 代码。

因此,如果您想在 a 中存储 alistStructure通过 Python C API 访问,只需存储一个 Python 即可——而且您一开始list真的不需要Structure;使用普通的 Python 类(可能带有__slots__)。您可以编写此代码而无需导入ctypes

相反,如果您想存储可以直接在 C 中使用的结构,您可以使用ctypes; 然后,在 C 代码中,一旦你深入Structure了解了,PyObject *你就不再需要 Python API,因为结构都是 C。当你有现有的 C 代码并且想要从 Python 与它交互,而不是在你从头开始设计 C 代码时,但是没有规则说你不能以其他方式使用它。

同时,如果这是您第一次尝试编写相互通信的 C 和 Python 代码,我建议您使用Cython. 然后,一旦您对此感到满意,如果您想学习ctypes,请做一个使用 Python 的不同项目来与ctypes对 Python 一无所知的 C 代码交谈。然后,第三个项目使用 C API 与一无所知的 Python 代码ctypes(如大多数 C 扩展模块)对话。一旦你熟悉了这三个,你就可以在未来为大多数项目选择正确的一个。

现在,回答具体问题:

首先,当PyList_GetItem(或 C API 中的大多数其他函数)返回 NULL 时,这意味着存在异常,因此您应该检查异常并记录它。尝试调试 C API 中的 NULL 返回值而不查看设置的异常就像尝试调试 Python 代码而不查看回溯一样。

无论如何,这个函数可能会失败有几个明显的原因:也许你正在使用越界索引调用它,或者你正在调用它根本不是 alist的东西。

事实上,第二个在这里似乎很明显。如果打印出来obj给你这个:

<ConfigurationParser.LP_LED object at 0x7f678a06fcb0>

然后你有一个(指向一个)LED对象,而LED对象不是lists。

如果您查看您的代码,您似乎在任何地方都没有list对象LED,至少在您向我们展示的代码中没有。你确实有一个POINTER(LED),它可以保存一个由 s 组成的 C 数组衰减的 C 数组LED,但这与它们中的 Pythonlist不同。它只是一个 C 数组,您可以使用 C 数组语法来取消引用:

PyObject *led = ledarray[i];
于 2012-12-12T18:17:12.433 回答