6

我正在尝试通过从 python 到 C++ 类方法的引用进行简单调用。

我的 C++ 代码如下所示:

class Foo {
protected:
  int _internalVal;
public:
  Foo() : _internalVal(5){}
  void getVal(int& val_io) {val_io = _internalVal;}
  void getValDoesNothing(int val_io) {val_io = _internalVal;}
}

我编译好的提升包装代码是:

BOOST_PYTHON_MODULE(libBar) {
  boost::python::class_<Foo>("Foo")
    .def("getVal", &Foo::getVal)
    .def("getValDoesNothing", &Foo::getValDoesNothing);
}

但是,当我进行以下 python 调用时:

In [1]: import libBar

In [2]: f = libBar.Foo()

In [3]: f
Out[3]: <libBar.Foo at 0x2b483c0>

In [4]: val = int()

In [5]: #next command is just to check function signature type

In [6]: f.getValDoesNothing(val)

In [7]: f.getVal(val)
---------------------------------------------------------------------------
ArgumentError                             Traceback (most recent call last)
<ipython-input-5-531e4cea97c2> in <module>()
----> 1 f.getVal(val)

ArgumentError: Python argument types in
    Foo.getVal(Foo, int)
did not match C++ signature:
    getVal(Foo {lvalue}, int {lvalue})

我正在使用我无法控制的库,因此更改 getVal 以返回值不是一种选择。

有没有办法让最后一个 Python 命令工作?

我什至会采取一个不改变 Python 变量但仍允许函数调用的修复程序。

4

3 回答 3

6

您要实现的目标在 Python 中无效。整数是不可变的,所以你不能简单地调用一个函数并希望它会改变它的内容。

由于您正在使用一个您无法控制的库并且更改 getVal 以返回该值不是一个选项,因此您可以创建一个这样的包装器:

int getVal(Foo &foo) {
    int val_io;
    foo.getVal(val_io);
    return val_io;
};

BOOST_PYTHON_MODULE(libBar) {
    boost::python::def("getVal", getVal);
    ...
}

然后以这种方式使用:

In [1]: import libBar

In [2]: f = libBar.Foo()

In [3]: f
Out[3]: <libBar.Foo at 0x2b483c0

In [3]: libBar.getVal(f)
Out[3]: 5
于 2012-12-05T19:04:55.997 回答
1

我使用带有单个元素的 numpy 数组来完成您正在尝试的操作。这是我在文件 ipc-messenger.h 中包装的类(在我的例子中,使用 MsgBuf 的 int 实现):

template <class MsgBuf>
class IPCMessenger {
public:
    IPCMessenger(const char* name);
    virtual ~IPCMessenger();
    virtual int Notify(const MsgBuf& msg, unsigned int priority = 0);
    int Receive(MsgBuf& msg, unsigned int* priority = nullptr);
    int Terminate();
private:
    boost::interprocess::message_queue _mq; /// boost IPC Message Queue.
    std::string _queue_name;                /// application defined queue name
};

这是 ipc-messenger_py.cpp 中的包装类

#include <boost/python.hpp>
#include "ipc-messenger.h"
#include <boost/python/numpy.hpp>

using namespace boost::python;
using namespace std;
namespace np = boost::python::numpy;

class IPCMessengerPy : public IPCMessenger<int> {
public:
    IPCMessengerPy(const char* name) : IPCMessenger(name) {}
    ~IPCMessengerPy() {}
    int Receive(np::ndarray & arr) {
        int ret = 0;
        int* p = (long *)arr.get_data();
        return IPCMessenger::Receive(*p);
    }
    int Notify(np::ndarray& arr) {
        int p = (long *)arr.get_data();
        return IPCMessenger::Notify(*p);
    }
};

BOOST_PYTHON_MODULE(ipcmessengerpy)
{
    Py_Initialize();
    np::initialize();

    class_<IPCMessengerPy, boost::noncopyable>("ipcmessenger", init<const char*>())
        .def( "receive", &IPCMessengerPy::Receive )
        .def( "send", &IPCMessengerPy::Notify )
        ;
}

这可以从 python 调用,如下所示:

import ipcmessengerpy
import numpy as np
import time

# run this script in background, and then run ipc-master.py

q = ipcmessengerpy.ipcmessenger("QueueName")
buf = np.zeros([1], dtype = np.int32)

for c in range(0, 10):
    q.receive(buf)
    print "Received ", buf[0], " on q"
于 2018-05-23T18:25:30.863 回答
-1

在 getValDoesNothing 中,您传递的是一个 int。在 getVal 中,您传递的是对 int 的引用。

我相信这是你问题的根源。

于 2012-12-05T17:11:14.693 回答