увеличить вызовы метода Python с помощью ссылочных аргументов

Я пытаюсь сделать простой вызов по ссылке из 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, но все же допускает вызов функции.

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
6

Другие решения

Я использую массив с одним элементом, чтобы выполнить то, что вы пытаетесь. Вот класс, который я обертываю (в моем случае, реализован с помощью int для MsgBuf) в файле ipc-messenger.h:

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"
1

В getVal ничего не передается в int.
В getVal вы передаете ссылку на int.

Я считаю, что это источник вашей проблемы.

-1
По вопросам рекламы ammmcru@yandex.ru
Adblock
detector