为什么PyObject_SetAttrString返回1(Python CAPI)

2024-09-25 02:38:54 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在处理C++和Python的桥接。在

<>当创建自定义类型的新实例时,我需要将某些C++实例方法登记为正在创建的Python对象的属性。在

相关的代码流程如下:

// during setup, we fill slots for the underlying PyTypeObject
p = new wrapperFor_PyTypeObject{ sizeof(FinalClass), 0, default_name };

p->set_tp_new(      extension_object_new );
p->set_tp_init(     extension_object_init );
p->set_tp_dealloc(  extension_object_deallocator );
:

这里感兴趣的是set_tp_init

^{pr2}$

支持PyObject* const char*str=m.first.c_str()

            Object callable{ m.second->ConstructCFunc(this) };  // ConstructCFunc uses PyCFunction_New
            callable.increment_reference_count();
            PyObject* c{ callable.ptr() };                      // extract backing PyObject* pointer

            int ret = PyObject_SetAttrString( a, str, c );

            if( ret == -1 )
                throw AttributeError{ m.first };
        }
    }

我以一种非常迂腐的方式声明了所有的变量,以确保它们正确地传递到PyObject_SetAttrString中,看起来确实是这样。在

但是,PyObject_SetAttrString返回-1(错误)。在

查看CPython源代码,我不知道这个错误是从哪里来的:

int
PyObject_SetAttrString(PyObject *v, const char *name, PyObject *w)
{
    PyObject *s;
    int res;

    if (Py_TYPE(v)->tp_setattr != NULL)
        return (*Py_TYPE(v)->tp_setattr)(v, (char*)name, w);
    s = PyUnicode_InternFromString(name);
    if (s == NULL)
        return -1;
    res = PyObject_SetAttr(v, s, w);
    Py_XDECREF(s);
    return res;
}

int
PyObject_SetAttr(PyObject *v, PyObject *name, PyObject *value)
{
    PyTypeObject *tp = Py_TYPE(v);
    int err;

    if (!PyUnicode_Check(name)) {
        PyErr_Format(PyExc_TypeError,
                     "attribute name must be string, not '%.200s'",
                     name->ob_type->tp_name);
        return -1;
    }
    Py_INCREF(name);

    PyUnicode_InternInPlace(&name);
    if (tp->tp_setattro != NULL) {
        err = (*tp->tp_setattro)(v, name, value); // <-- SHOULD HIT HERE
        Py_DECREF(name);
        return err;
    }
    if (tp->tp_setattr != NULL) {
        char *name_str = _PyUnicode_AsString(name);
        if (name_str == NULL)
            return -1;
        err = (*tp->tp_setattr)(v, name_str, value);
        Py_DECREF(name);
        return err;
    }
    Py_DECREF(name);
    assert(name->ob_refcnt >= 1);
    if (tp->tp_getattr == NULL && tp->tp_getattro == NULL)
        PyErr_Format(PyExc_TypeError,
                     "'%.100s' object has no attributes "
                     "(%s .%U)",
                     tp->tp_name,
                     value==NULL ? "del" : "assign to",
                     name);
    else
        PyErr_Format(PyExc_TypeError,
                     "'%.100s' object has only read-only attributes "
                     "(%s .%U)",
                     tp->tp_name,
                     value==NULL ? "del" : "assign to",
                     name);
    return -1;
}

除了必须将CPython源代码添加到我的项目中并一步一步地完成它之外,还有什么可以尝试的吗?在

通过查看输入的值,它应该达到我标记的点:

    PyUnicode_InternInPlace(&name);
    if (tp->tp_setattro != NULL) {
        err = (*tp->tp_setattro)(v, name, value); // <-- SHOULD HIT HERE
        Py_DECREF(name);
        return err;
    }

但我不知道如何调试到tp_setattro中。它是函数表中的一个槽。对源代码进行greping会显示出大量的访问。在


Tags: namepyreturnifobjectvaluenullint