【问题标题】:Using a new type in Python C Extension在 Python C 扩展中使用新类型
【发布时间】:2013-11-22 05:01:50
【问题描述】:

我已经编写了代码来在 Python C 扩展 (MyStatus) 中定义一个新类型。 如page 中所述,我编写了 C 代码来定义分配、解除分配等。

我能够编译模块并从 python 中使用它。

现在我正在尝试在另一个 Python C 扩展 (TestStatus) 中使用这种新类型 我的要求是我只需要一个.so。 我不想直接从 Python 代码中使用 MyStatus。 我将只在我的代码中导入 TestStatus,并且我想从为 TestStatus 编写的 C 扩展中初始化 MyStatus。

我已经为 TestStatus 编写了这样的代码

static PyObject * TestStatus_checkPyObject *self, PyObject *args)
{
    PyObject * mystatus = NULL;
    const char *command;

    /* Call the class object. */
    mystatus = PyObject_CallObject((PyObject *) &MyStatusType, NULL);

    return mystatus;
}

    PyMODINIT_FUNC initTestStatus(void)
    {
        (void) Py_InitModule("TestStatus", TestMethods);

        initMyStatus();//This is available in the C code written for MyStatus
    }

我能够像我在代码中提到的那样创建。 但我坚持为 MyStatus 设置变量,它是一个整数和 char*(PyObject*) 有人可以对此有所了解,例如我的方法是否正确以及如何通过参数初始化和使用来自 TestStatus 的 MyStatus。

我正在 Rhel 6.3 上使用 Python 2.6.6 尝试此操作

在 MyStatus 中我有 2 个变量

typedef struct {
    PyObject_HEAD
    int         mStatus;
    PyObject    *mErrorString;
} MyStatus;

我需要从 TestStatus 初始化它。

【问题讨论】:

  • 你被困在设置“变量”上,哪些变量?你能更具体一点吗,那会有所帮助。为什么只需要 .so 文件?如果将两个模块的代码放在一个文件中,它会起作用吗? - 抱歉,但我没有放弃解决问题,所以很难解释清楚。
  • 我已经编辑了帖子以添加有关变量的信息。

标签: python-2.7 python-c-extension


【解决方案1】:

Python C 扩展应提供C-API 以供其他 C 模块使用。所以在你的情况下,你的MyStatus.h 应该有一些东西,比如

/* Header file for MyStatus module */

#ifndef MyStatus_MODULE_H
#define MyStatus_MODULE_H
#ifdef __cplusplus
extern "C" {
#endif

typedef struct {
    PyObject_HEAD
    int         mStatus;
    PyObject    *mErrorString;
} MyStatus;

#define MyStatus_Type_NUM 0

#define MyStatus_New_NUM 1
#define MyStatus_New_RETURN MyStatus *
#define MyStatus_New_PROTO (int mStatus, PyObject *mErrorString)

/* Total number of C API pointers */
#define MyStatus_API_pointers 2

#ifdef MyStatus_MODULE
/* do nothing for this minimal example */
#else

static void **MyStatus_API;

#define MyStatus_Type (*(PyTypeObject *)(\
    MyStatus_API[MyStatus_Type_NUM]))

#define MyStatus_New \
 (*(MyStatus_New_RETURN (*)MyStatus_New_PROTO) \
  MyStatus_API[MyStatus_New_NUM])

static int import_MyStatus(void)
{
    MyStatus_API = (void **)PyCapsule_Import("MyStatus._C_API", 0);
    return (MyStatus_API != NULL) ? 0 : -1;
}
#endif /* !defined(MyStatus_MODULE) */
#ifdef __cplusplus
}
#endif
#endif /* !defined(MyStatus_MODULE_H) */

并定义类似

static Py MyStatus *
PyMyStatus_New(int mStatus, PyObject *mErrorString){
    MyStatus *self;
    self = (MyStatus *)MyStatusType.tp_alloc(&MyStatusType, 0);
    self->mStatus = mStatus;
    Py_INCREF(mErrorString); // in case you don't want to steal a reference
    self->mErrorString = mErrorString;
    if (!self->mErrorString){
        Py_DECREF(self);
        return NULL;
    }
    return self;
}

#ifndef PyMODINIT_FUNC  /* declarations for DLL import/export */
#define PyMODINIT_FUNC void
#endif PyMODINIT_FUNC initMyStatus(void){
    PyObject *m = Py_InitModule3("MyStatus", methods, "");
    static void *MyStatus_API[MyStatus_API_pointers];

    MyStatus_API[MyStatus_Type_NUM] = (void *)&MyStatusType;
    MyStatus_API[MyStatus_New_NUM] = (void *)MyStatus_New;

    PyObject *c_api_object = PyCapsule_New((void *)MyStatus_API, "MyStatus._C_API", NULL);
    if (c_api_object != NULL) PyModule_AddObject(m, "_C_API", c_api_object); }

MyStauts.c。此外,它非常方便 定义宏,如

PyMyStatus_SET_MSTATUS(self, mStatus)
PyMyStatus_GET_MSTATUS(self)
PyMyStatus_SET_mErrorString(self, mErrorString)
PyMyStatus_GET_mErrorString(self)

以后能够更改 MyStatus 的底层结构并处理引用计数。

如果您不想这样做,您始终可以直接初始化和修改MyStatus 对象,如上例中MyStatus_New 函数所示。

TestStatus.c 最后导入C-API。

PyMODINIT_FUNC initTestStatus(void){
    import_MyStatus();
    Py_InitModule3("TestStatus", methods, "");

}

现在您可以使用MyStatus_NewMyStatusType

【讨论】:

  • 我将此代码作为 MyStatus 的一部分。但我的疑问是我应该如何从 TestStatus 中调用它。如您所见,我正在调用 initMyStatus。但是在 TestStatus 的方法中,我应该初始化一个 MyStatus 的对象,用错误字符串和状态初始化它。这就是我卡住的地方
  • 我明白了。我认为问题在于您尝试在initTestStatus 中调用initMyStatus();。您需要调用必须在MyStatus 模块中定义的import_MyStatus(); 来导入C-API。然后,您可以在 TestStatus 中调用来自 MyStatus 的函数,并使用通过 C-API 导出的类型。
  • 会试试这个,让你知道...感谢您的意见
  • 您的尝试成功了吗?
  • 您应该能够将所有内容放在一个文件中,MyStatus 类型和 TestStatus 类型的定义。在这种情况下,您甚至不需要显式导入 C-API。但是,您创建和与 MyStatus 对象交互的方式应该保持不变,例如通过PyMyStatus_New。我不明白的是,如果您不想将MyStatus 暴露给python,为什么它应该是python 类型。在那种情况下,我将只使用普通的 C 结构和函数,而不是处理复杂的 python C-API。
猜你喜欢
  • 1970-01-01
  • 2021-11-22
  • 1970-01-01
  • 2011-02-04
  • 1970-01-01
  • 2010-11-07
  • 2011-12-01
  • 2019-03-28
  • 1970-01-01
相关资源
最近更新 更多