【问题标题】:Using multiple modules/types with Python C API?在 Python C API 中使用多个模块/类型?
【发布时间】:2010-01-25 22:57:37
【问题描述】:

我有两个不同的 Python 扩展模块;我们称它们为 A 和 B。模块 A 包含一个称为容器的存储类类型,我想在模块 B 中将其用作类方法的返回类型。

我似乎找不到任何关于我应该如何执行此操作的文档。我大致按照这篇文章创建模块/类,除了我没有将所有方法声明为静态,因此它们可以访问:http://nedbatchelder.com/text/whirlext.html

我的问题是,如何创建一个容器实例,我可以将它作为模块 B 中类方法的 PyObject* 返回值传回?容器定义如下所示:

typedef struct {
    PyObject_HEAD

    storageclass* cnt_;
} container;

我尝试在相关方法中简单地执行以下操作,其中 container_init 是我为容器类注册为 tp_init 的方法:

pycnt::container* retval;
pycnt::container_init(retval, NULL, NULL);
return (PyObject*)retval;

但是,根据 Python 解释器,我正在取回调用该方法的类。 (即 myclassinstance.mymethod() 正在返回 myclassinstance)。

我显然走错了路,但我不知道正确的方法是什么。有什么建议么?只是为了切断任何人的建议——不,我对使用 SWIG 或 Boost::Python 不感兴趣。我已经尝试过了,容器的底层存储类也不能很好地使用(SWIG 甚至无法解析它)。到目前为止,我自己做的扩展非常轻松,但我被这个难住了。

【问题讨论】:

    标签: python c binding python-c-api python-extensions


    【解决方案1】:

    你的问题是type->tp_init 没有做你想做的事。 type->tp_init 在分配对象以进行实例化后调用。您首先必须使用type->tp_new 分配对象,然后将该对象作为第一个参数传递给type->tp_init。由于您将未初始化的指针传递给tp_init,因此所有赌注都已关闭。不过,您通常不会直接调用任何一个函数,而是在类型对象本身上调用 PyObject_Call*() 之一来创建新实例。或者提供一个普通的 C 函数来创建一个新实例,例如 PyFoo_New()

    也就是说,在两个扩展模块之间进行相互通信的常用方法是通过 Python API 来实现。如果您希望模块 B 导入和使用模块 A,则调用 PyImport_Import() 获取模块对象,调用 PyObject_GetAttrString() 获取您关心的类型对象,并调用 PyObject_Call*() 之一来实例化它。任何你想存储指向该类型的指针的地方,你只需要一个PyObject *

    【讨论】:

    • 我最终组合了模块并为每种类型编写了 PyFoo_New() 方法,现在一切正常。但是有一个问题,在我将模块组合成一个模块之前,我尝试在另一个模块中使用我的 PyContainer_New() 方法,虽然解释器报告我正在取回一个容器对象,但我无法调用它的任何方法。这是为什么?我已经导入了容器模块,但仍然没有运气。
    • 那里没有足够的信息来进行充分的分析,但是我猜你是两次包含第一个模块的代码,一次是作为正在导入的共享对象,一次是通过另一个模块中的依赖项(静态或动态链接)。调用第二次出现的 PyContainer_New() 将为您提供各种未初始化的数据结构。
    猜你喜欢
    • 2017-06-13
    • 1970-01-01
    • 1970-01-01
    • 2018-08-31
    • 2011-02-07
    • 1970-01-01
    • 1970-01-01
    • 2012-05-04
    • 1970-01-01
    相关资源
    最近更新 更多