You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PySide6+Python C API:继承QRasterWindow调用metric触发EXC_BAD_ACCESS错误

环境信息

  • Python版本:3.9.6 (default, May 7 2023, 23:32:45)
  • PySide6版本:6.7.0

问题现象

  1. 直接创建QRasterWindow实例并调用metric方法时运行正常:
Py_Initialize();

    PyObject * GUI = PyImport_ImportModule("PySide6.QtGui");
    if(!GUI) {
        printf("\nCould not import PySide6.QtGui module.\n");
        return 0;
    }

    // QApplication
    PyObject* QGA = PyObject_GetAttrString(GUI, "QGuiApplication");
    PyObject * argsqa = PyTuple_New (1);
    PyObject * listqa = PyList_New (1);
    PyList_SetItem (listqa, 0, PyUnicode_FromString (""));
    PyTuple_SetItem (argsqa, 0, listqa);
    PyObject * res = PyObject_CallObject(QGA, argsqa);

    // QRasterWindow
    PyObject* QRW = PyObject_GetAttrString(GUI, "QRasterWindow");
    if(QRW) {

        // Create instance
        PyObject * args = PyTuple_New (0);
        PyObject * QRW_inst = PyObject_CallObject(QRW, args);
             
        // Call metric
        PyObject * mm = PyObject_GetAttrString(QRW_inst, "metric");

        PyObject * uu = PyObject_GetAttrString(GUI, "QPaintDevice");
        PyObject * ww = PyObject_GetAttrString(uu, "PdmWidth");

        PyObject * argsm = PyTuple_New (1);
        PyTuple_SetItem (argsm, 0, ww);
        PyObject * res = PyObject_CallObject(mm, argsm);

        int val = PyLong_AsLong(res);
        printf("\nQRasterWindow.metric value is %d \n", val);

    } else {
        printf("\nCould not get QRW class.\n");
    }
  1. 但创建继承自QRasterWindow的PCJ类,实例化后调用metric方法时触发段错误EXC_BAD_ACCESS:
// Create PCJ class inherited from QRasterWindow
    PyType_Slot slots[] = {
        { Py_tp_doc, "PGJ" },
        { Py_tp_base, QRW },
        { Py_tp_init, QRW_init },
        { 0 },
    };
    PyType_Spec spec = { "PCJ", 0, 0,
                          Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots };
    PyTypeObject *PCJ = (PyTypeObject *)PyType_FromSpec(&spec);
    printf("\nPCJ value is %d \n", PCJ);

    // Create PCJ instance
    PyObject * argsj = PyTuple_New (0);
    PyObject * PCJ_inst = PyObject_CallObject((PyObject *) PCJ, argsj);
    printf("\nPCJ_inst value is %d \n", PCJ_inst);
         
    // Call metric
    PyObject * mm = PyObject_GetAttrString(PCJ_inst, "metric");
    printf("\nmm value is %d \n", mm);

    PyObject * uu = PyObject_GetAttrString(GUI, "QPaintDevice");
    printf("\nuu value is %d \n", uu);
    PyObject * ww = PyObject_GetAttrString(uu, "PdmWidth");
    printf("\nww value is %d \n", ww);

    PyObject * argsm = PyTuple_New (1);
    PyTuple_SetItem (argsm, 0, ww);
    PyObject * resj = PyObject_CallObject(mm, argsm); // segmentation fault
    printf("\nresj value is %d \n", resj);

    int valj = PyLong_AsLong(resj);
    printf("\nPCJ.metric value is %d \n", valj);

问题原因及解决方法

问题核心在于你自定义的PCJ类没有正确完成Qt底层C++对象的初始化流程:

  1. 错误指定了Py_tp_init:你设置的QRW_init函数如果没有调用父类QRasterWindow的初始化逻辑,会导致PCJ实例对应的Qt底层对象根本没被创建,调用metric方法时自然会访问无效内存触发段错误。
  2. 类型未完成初始化:创建自定义类型后没有调用PyType_Ready,导致类型内部结构未完全就绪。

修复方案:

方案1:去掉自定义初始化逻辑(推荐,无特殊需求时用)

直接删除{ Py_tp_init, QRW_init }这个slot,让Python自动调用父类的初始化方法:

// Create PCJ class inherited from QRasterWindow
PyType_Slot slots[] = {
    { Py_tp_doc, "PGJ" },
    { Py_tp_base, QRW },
    { 0 },
};
PyType_Spec spec = { "PCJ", 0, 0,
                      Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, slots };
PyTypeObject *PCJ = (PyTypeObject *)PyType_FromSpec(&spec);
// 关键:确保类型准备就绪
if (PyType_Ready(PCJ) < 0) {
    printf("\nFailed to initialize PCJ type.\n");
    return 0;
}
// 注意:打印指针要用%p,别用%d
printf("\nPCJ value is %p \n", PCJ);
方案2:保留自定义初始化(需正确调用父类逻辑)

如果一定要自定义初始化函数,必须确保调用父类的__init__:

static int QRW_init(PyObject *self, PyObject *args, PyObject *kwds) {
    // 调用父类的初始化方法
    PyTypeObject *base_type = (PyTypeObject*)Py_TYPE(self)->tp_base;
    if (base_type->tp_init != NULL) {
        int res = base_type->tp_init(self, args, kwds);
        if (res < 0) return res;
    }
    // 这里加你的自定义初始化逻辑
    return 0;
}

// 后续创建类型的代码中保留Py_tp_init slot,同时必须调用PyType_Ready

另外,代码中用%d打印指针地址是错误的,统一换成%p才能正确显示指针值,避免输出混乱。

内容的提问来源于stack exchange,提问作者Blady

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.19 09:12:39