调用PyObject_VectorcallMethod报错:Class.set_params()参数'a'多值冲突
问题原因分析
你遇到的TypeError是因为C代码中参数传递方式完全错误,导致Python的set_params函数同时收到了a的位置参数和关键字参数,触发重复参数报错。具体错误点:
- 参数打包错误:用
Py_BuildValue("i", 77, "i", 20)生成参数完全错误,格式字符串与参数数量不匹配,且PyObject_VectorcallMethod不需要将参数打包成单个对象,需直接将参数值放入args数组。 - args数组构造错误:你把错误打包的
keyfunc作为位置参数传递,同时指定了kwnames,导致函数既收到位置参数(77被当作a的位置值)又收到a=77的关键字参数,造成重复。 - nargsf计算错误:错误设置了位置参数数量,未正确标记关键字参数的数量。
修正后的C代码
// 创建方法名 PyObject *name = Py_BuildValue("s", "set_params"); // 创建关键字参数名称元组 PyObject *kwnames = Py_BuildValue("(s,s)", "a", "b"); // 准备参数值:实例 + 关键字参数值(顺序与kwnames对应) PyObject *arg_a = PyLong_FromLong(77); PyObject *arg_b = PyLong_FromLong(20); PyObject *args[] = { pInstance, arg_a, arg_b }; // 计算nargsf:0个位置参数 | 2个关键字参数 | 包含实例标志 size_t nargsf = 0 | (2 << PY_VECTORCALL_KW_SHIFT) | PY_VECTORCALL_ARGUMENTS_OFFSET; // 调用方法 PyObject *ret = PyObject_VectorcallMethod(name, args, nargsf, kwnames); // 释放引用 Py_DECREF(arg_a); Py_DECREF(arg_b); Py_DECREF(kwnames); Py_DECREF(name);
关键说明
args数组结构:第一个元素是实例对象,后面依次是位置参数值(如有),再后面是关键字参数值(顺序必须与kwnames中的名称一一对应)。nargsf计算规则:- 低8位(
PY_VECTORCALL_ARGUMENTS_MASK)是位置参数的数量(不含实例)。 - 关键字参数数量通过
kw_count << PY_VECTORCALL_KW_SHIFT计算。 PY_VECTORCALL_ARGUMENTS_OFFSET标志表示args[0]是实例对象(方法调用必须带此标志)。
- 低8位(
- 所有通过
PyLong_FromLong等函数创建的临时对象,必须手动调用Py_DECREF释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者user1514692
相关产品推荐
相关产品推荐

