使用pybind11调用嵌入功能中的方法

问题描述 投票:2回答:2

我正在使用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,或者我刚刚拧了整个事情了。

任何有识之士将不胜感激。

c++ python-3.x
2个回答
2
投票

这也提起与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在此范围内保持该值。


1
投票

所以经过一些实验,我发现这个问题是由pybind不能够检测到功能范围之外的进口模块引起的。

import foo

def bar():
  foo.func()

总是会导致一个错误。然而,

def bar():
  import foo
  foo.func()

如预期会发挥作用。

© www.soinside.com 2019 - 2024. All rights reserved.