在 C++ 中对 PyObject 调用"+="

Call `+=` on a PyObject in C++

本文关键字:quot 调用 C++ 中对 PyObject      更新时间:2023-10-16

我正在用C++编写一个Python模块。

在某个时候,我需要将任意类型的PyObject添加到另一个。换句话说,做a += b在Python中所做的同样的事情。但是我无法在 API 中找到执行此操作的函数。

我尝试执行以下操作,

PyObject* increment(PyObject* a, PyObject* b) {
const auto tp = Py_TYPE(a);
[&]{
if (const auto nb = tp->tp_as_number)
if (auto iadd = nb->nb_inplace_add)
return iadd;
if (const auto sq = tp->tp_as_sequence)
if (auto iadd = sq->sq_inplace_concat)
return iadd;
throw error(PyExc_TypeError,
"type "s+(tp->tp_name)+" does not provide __iadd__");
}()(a,b);
return a;
}

但发现 Python 既没有float,也没有int,也没有str实现这些方法。

API 中是否有应用通用+=的函数?如果没有,我该怎么写?

在某个时候,我需要将任意类型的 PyObject 添加到另一个 PyObject 中。换句话说,做与 += b 在 Python 中所做的相同操作。但是我无法在 API 中找到执行此操作的函数。

您找不到的功能是PyNumber_InPlaceAdd.

x += y

在 Python 级别相当于

sum = PyNumber_InPlaceAdd(x, y);
Py_DECREF(x);
x = sum;

在 C 级别。(如果需要,还可以同时保留sumx,这对于异常处理非常有用。

PyNumber_InPlaceAdd处理+=的完整调度逻辑,包括__iadd__、双方的__add__方法(按正确的顺序(、NotImplemented哨兵和nb_inplace_addnb_addsq_inplace_concatsq_concatC级钩子。

我最终做了这样的事情:

static PyObject* increment(PyObject*& a, PyObject* b) {
const auto tp = Py_TYPE(a);
if (const auto nb = tp->tp_as_number) {
if (auto iadd = nb->nb_inplace_add)
return iadd(a,args), a;
if (auto add = nb->nb_add)
return a = add(a,b);
}
if (const auto sq = tp->tp_as_sequence) {
if (auto iadd = sq->sq_inplace_concat)
return iadd(a,b), a;
if (auto add = sq->sq_concat)
return a = add(a,b);
}
throw error(PyExc_TypeError,
"cannot increment "s+(tp->tp_name)+" by "+(Py_TYPE(b)->tp_name));
}

正如让-弗朗索瓦·法布尔所建议的那样,如果没有__iadd__,那就是__add__