我正在使用pybind11嵌入蟒蛇C ++应用程序,我已经尝试调用从类方法的嵌入式功能时遇到了一点问题。
先从这里是我的绑定:
#ifdef _DEBUG
#undef _DEBUG
#include <python.h>
#define _DEBUG
#else
#include <python.h>
#endif
#include <embed.h>
namespace py = pybind11;
using namespace py::literals;
void DebugInfo(std::string string_)
{
String LogMessage_(string_.c_str());
LOGINFO(LogMessage_);
}
PYBIND11_EMBEDDED_MODULE(Test, m) {
m.def("DebugInfo", &DebugInfo, "Posts message to DEBUGINFO");
}
那么我可以有一个.py文件:
import Test
test.DebugInfo("I'm a lumberjack and that's OK")
它将打印就好调试
麻烦的开始,当我试图从一个类的方法中调用它。
import Test
class PyTest(object):
def __init__(self):
test.DebugInfo("I'm a lumberjack and that's OK")
test = PyTest()
当该运行抛出异常针对cast.h特异性针对1985线作为本功能的一部分:
template <return_value_policy policy>
class unpacking_collector {
public:
template <typename... Ts>
explicit unpacking_collector(Ts &&...values) {
// Tuples aren't (easily) resizable so a list is needed for collection,
// but the actual function call strictly requires a tuple.
auto args_list = list();
int _[] = { 0, (process(args_list, std::forward<Ts>(values)), 0)... };
ignore_unused(_);
m_args = std::move(args_list);
}
const tuple &args() const & { return m_args; }
const dict &kwargs() const & { return m_kwargs; }
tuple args() && { return std::move(m_args); }
dict kwargs() && { return std::move(m_kwargs); }
/// Call a Python function and pass the collected arguments
object call(PyObject *ptr) const {
PyObject *result = PyObject_Call(ptr, m_args.ptr(), m_kwargs.ptr());
if (!result)
throw error_already_set(); //EXCEPTION THROWS HERE!
return reinterpret_steal<object>(result);
}
而且,因为它可能与此有关就是我打电话是从我的主应用程序的整个事情
//Start the Python Interpreter
py::scoped_interpreter guard{};
//Python variables
py::object thing_;
std::string test_py = Import_File("test.py");
auto locals = py::dict();
py::exec(test_py, py::globals(), locals);
thing_ = locals["test"].cast<py::object>();
thing_.attr("start")();
和test.py内容
import Test
class PyTest(object):
def __init__(self, message = "Test Object initialized"):
self.message = message
iterstr = str(self.iter)
message = self.message + iterstr
self.iter = 0
Test.DebugInfo(message)
def start(self):
self.message = "Starting Python Object"
self.iter = self.iter + 1
iterstr = str(self.iter)
message = self.message + iterstr
Test.DebugInfo(message)
def update(self):
self.message = "Python Object Update Cycle:"
self.iter = self.iter + 1
iterstr = str(self.iter)
message = self.message + iterstr
Test.DebugInfo(message)
test = PyTest()
我不知道如果我在它碰上pybind11的限制,一个bug,或者我刚刚拧了整个事情了。
任何有识之士将不胜感激。
这也提起与pybind11
这里的一个问题:https://github.com/pybind/pybind11/issues/1452
我碰到这两个SO和问题,但我想通了这一点。这里复制的人谁碰到这个第一次在未来绊倒
基本上,你实际上并不想为py::dict
空白locals
;它会导致各种问题。如果你看看从文档或测试,locals
值始终份全球范围内嵌入示例代码。
看到:
* https://pybind11.readthedocs.io/en/stable/advanced/embedding.html
* https://github.com/pybind/pybind11/blob/master/tests/test_embed/test_interpreter.cpp#L57
您的选择是复制全球范围内,或者,在这种情况下,根本就没有在locals
通
py::scoped_interpreter guard{};
auto globals = py::globals();
py::exec(test_py, globals);
thing_ = globals["Object"].cast<py::object>();
thing_.attr("start")();
这看起来在顶级代码(未任何模块内)的情况下,可变globals
在此范围内保持该值。
所以经过一些实验,我发现这个问题是由pybind不能够检测到功能范围之外的进口模块引起的。
import foo
def bar():
foo.func()
总是会导致一个错误。然而,
def bar():
import foo
foo.func()
如预期会发挥作用。