首页 > 解决方案 > Python 对象未使用 C API 完全初始化

问题描述

在以下场景中,该对象不打算在 Python 中实例化(因此没有tp_newor tp_init)。我相信,将 ThingType 作为函数调用会PyObject_CallObject导致 in 中的段错误_PyObject_FastCallDict,因为没有构造函数。

使用 CreatePythonThing 创建对象后,get_height除非应用变通方法,否则不会设置该函数 - 调用dir(thing),作为副作用初始化对象的属性。解决方法已经存在于CreatePythonThing.

#include <Python.h>

typedef struct {
    PyObject_HEAD
    /* Type-specific fields go here. */
    Eval *eval;
} Thing;

static PyObject* ThingGetHeight(PyObject* self, PyObject* args)
{
    return PyLong_FromLong(1);
}

static PyMethodDef ThingMethods[] = {
    {"get_height", ThingGetHeight, METH_NOARGS, "Get thing height"},
    {NULL, NULL, 0, NULL}        /* Sentinel */
};

static PyTypeObject ThingType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "thing.Thing",             /* tp_name */
    sizeof(Thing),             /* tp_basicsize */
    0,                         /* tp_itemsize */
    0,                         /* tp_dealloc */
    0,                         /* tp_print */
    0,                         /* tp_getattr */
    0,                         /* tp_setattr */
    0,                         /* tp_reserved */
    0,                         /* tp_repr */
    0,                         /* tp_as_number */
    0,                         /* tp_as_sequence */
    0,                         /* tp_as_mapping */
    0,                         /* tp_hash */
    0,                         /* tp_call */
    0,                         /* tp_str */
    0,                         /* tp_getattro */
    0,                         /* tp_setattro */
    0,                         /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT,        /* tp_flags */
    "Thing",                   /* tp_doc */
    0, 0, 0, 0, 0, 0,
    ThingMethods,              /* tp_methods */
};


Thing* CreatePythonThing(Eval *eval)
{
    Thing* obj = PyObject_New(Thing, &ThingType);
    obj->eval = eval;
    obj = (Thing*) PyObject_Init((PyObject*) obj, &ThingType);
    // I don't understand why, but the above does not fully initialize the object. The method
    // table is not set. Calling `dir` on the object causes it to be initialized, so this is 
    // a workaround.
    PyObject_Dir((PyObject*) obj);
    return obj;
}

标签: pythoncpython-c-api

解决方案


正如 DavidW 的评论一样,我PyType_Ready(&ThingType);的全局初始化程序中缺少我。


推荐阅读