【问题标题】:C++ to numpy and back to C++, tuple PyObjectC++ 到 numpy 并返回到 C++,元组 PyObject
【发布时间】:2015-04-22 17:16:51
【问题描述】:

我正在实现一个 Visual C++ 代码 (MS VStudio 2013),它从相机获取图像、处理图像、通过 PyObject 将预处理数据(数组 2 或更多双精度数)发送到 python,并获取 numpy-从python返回的处理结果(py中的3个双精度元组,在C++中变成3个双精度数的数组)。我将 py 函数作为独立脚本进行了测试。但是,我不断从 PyObject_CallObject() 返回 null。 python和VC++项目在同一个目录下。

我已经在 py 函数中设置了一个日志文件记录来记录来自 C 的调用,所以我知道在某些情况下 C++ 调用不会到达 py 函数,而在其他情况下会调用 py 函数,但是,可能无法处理返回的值。具体来说,我发现当元组包含一个对象时我可以调用py函数(正日志记录),但是当元组包含两个或多个对象时我不能调用它(没有日志文件记录)。另外,如果py函数不需要参数,也不需要返回任何东西,那么所有调用都是成功的。

我已经用谷歌搜索并阅读了所有与使用元组在 C++ 和 py 之间进行通信有关的内容,但仍然没有成功。我也阅读了文档和示例,仍然没有运气。

我已将代码剥离到最低限度并重现了该问题。下面是一个示例,当我将两个零作为输入传递并期望得到三个零时。我将非常感谢这方面的任何线索...

//C++ part
    Py_Initialize();    
    pyName = PyImport_ImportModuleNoBlock(_T("find_center_def"));
    if (pyName == NULL) {       
        return false;
    }
    pyFunc = PyObject_GetAttrString(pyName, _T("find_center"));
    if (pyFunc == NULL) {
        return false;
    }
    Py_DECREF(pyName);
    if (PyCallable_Check(pyFunc) == 0) {
        return false;
    }
    PyObject * arg = PyTuple_New(2);
    PyObject * datum0 = PyFloat_FromDouble(0.0);
    PyObject * datum1 = PyFloat_FromDouble(0.0);
    if (PyTuple_SetItem(arg, 0, datum0) != 0) {
        return false;
        }
    if (PyTuple_SetItem(arg, 1, datum1) != 0) {         
        return false;
        }
    PyObject * result = PyObject_CallObject(pyFunc, arg);
    if (result == NULL) {
        return false;
    }
    OutputDebugString(_T("\nSuccess calling find_center function!"));

#python part, inside of a script called find_center_def.py
def find_center(args):
    import numpy        
    fo=open('foo.txt' ,'w')
    fo.write('find_center was called from C++!')
    fo.close()
    return (0,0,0)

#python output:
Python 3.4.3 (v3.4.3:9b73f1c3e601, Feb 24 2015, 22:44:40) [MSC v.1600 64 bit (AMD64)] on win32
>>> import importlib
>>> test = importlib.import_module("find_center_def")
>>> test.find_center((0,0))
(0, 0, 0)
>>>

【问题讨论】:

  • PyObject_GetAttrString(pyName, _T("find_center"))PyTuple_SetItem(arg, 1, datum1) 是否返回 0?
  • Adam -- 它们都返回 0(即成功),代码一直运行到最终的 NULL== 结果。
  • 不知道这是否是一个线索,但如果我让 py 函数返回任何非零数字(比如 15),C++ 会用零替换它:\nPyObject * result = PyObject_CallObject(pyFunc , arg);int final_result = PyLong_AsLong(result); (最终结果总是 0,如果我使用双精度则为 0.0)
  • 我对自己的回复表示歉意。我发现如果我通过调用 PyObject * arg = Py_BuildValue("(d)", 5.0); 来简化 PyTuple 参数的制作,症状仍然存在——当元组长度为 1 时调用成功(格式字符串中有一个 d ),但当元组长度大于 1(格式字符串中有两个或多个 ds)时失败。响应被归零,但不确定是否是同一问题的一部分。
  • Adam -- 是的,该函数是可调用的,并且在最后一次调用之前所有的完整性检查都可以。我部分通过将 PyObject_CallObject 的参数设置为大小为 1 的元组来解决该问题,其中包含一个大小为 N 的双精度列表。我从未设法使用大小>1 的元组调用 PyObject_CallObject作为论据。我现在收到了回复,包含在三个双精度元组中(到目前为止,解析时只给我 0.0 - 可能是 unicode 问题)

标签: python c++ numpy pyobject


【解决方案1】:

你只能向你的元组添加一个值,因为

PyObject* PyObject_CallObject(PyObject *callable_object, PyObject *参数) 调用一个可调用的 Python 对象 callable_object,使用元组 args 给出的参数

(强调我的)。换句话说,PyObject_CallObject 的第二个参数是参数的元组。您的函数采用单个参数,因此该元组的长度必须为 1。

由于您尝试将元组作为一个参数传递,因此您需要将双元素元组作为您作为第二个参数传递给 PyObject_CallObject 的单元素元组的第一个元素。

另一种选择是改用PyObject_CallFunction,并让它构建参数元组。

【讨论】:

  • 亚当,是的,我通过实验得到了它,现在我明白了。可能是文档可以更明确地说明元组的长度应该为 1。从我发现的使用 PyTuple_SetItem 的示例中,这并不明显,因为后者使用的项目索引> 0。无论如何,使用 PyObject * arg = Py_BuildValue("(O)", list) 来制作我的输入元组,其中 list 是由 PyList_SetItem 构建的,可以正常工作。正如你所说,list 也可能是 N 元素元组。
  • 还有一件事……python 的返回格式是正确的,但我得到了零,因为我的 VS2013 默认为 Unicode,而我使用的是非 Unicode 方法来报告值。
猜你喜欢
  • 2015-08-03
  • 2011-09-23
  • 1970-01-01
  • 1970-01-01
  • 2017-02-22
  • 2016-03-23
  • 2013-07-12
  • 2018-10-07
相关资源
最近更新 更多