python - 使用 boost-python 将 python 变量设置为 C++ 对象指针

标签 python c++ boost boost-python

我想从 C++ 设置一个 Python 变量,以便 C++ 程序可以创建一个对象 Game* game = new Game(); 以便 Python 代码能够引用这个实例(和调用函数等)。我怎样才能做到这一点?

我觉得我对 Python 或 Boost-Python 的工作方式有一些核心误解。

main_module.attr("game") = game 行在 try catch 语句中,错误(使用 PyErr_Fetch)是“No to_python (by-value) converter found for C++ type : 类游戏"。

例如

class_<Game>("Game")
        .def("add", &Game::add)
;

object main_module = import("__main__");
Game* game = new Game();
main_module.attr("game") = game; //This does not work

来自 Python:

import testmodule

testmodule.game.foo(7)

最佳答案

在处理语言绑定(bind)时,人们常常不得不在细节上迂腐。默认情况下,当 C++ 对象越过语言边界时,Boost.Python 将创建一个拷贝,因为这是防止悬挂引用的最安全的操作过程。如果不应制作拷贝,则需要明确 C++ 对象的所有权:

  • 要在保持 C++ 所有权的同时将 C++ 对象的引用传递给 Python,请使用 boost::python::ptr()boost::ref() . C++ 代码应保证 C++ 对象的生命周期至少与 Python 对象一样长。使用 ptr() 时,如果指针为空,则生成的 Python 对象将为 None
  • 要将 C++ 对象的所有权转移给 Python,可以应用 manage_new_object ResultConverterGenerator ,允许将所有权转移给 Python。一旦 Python 对象的生命周期结束,C++ 代码不应尝试访问指针。
  • 对于共享所有权,需要使用 HeldType 公开类支持共享语义的智能指针,例如 boost::shared_ptr

创建 Python 对象后,需要将其插入到 Python 命名空间中才能普遍访问:

  • 在模块定义中,使用 boost::python::scope获取当前作用域的句柄。例如,以下将插入 xexample 模块中:

    BOOST_PYTHON_MODULE(example)
    {
      boost::python::scope().attr("x") = ...; // example.x
    }
    
  • 要插入到__main__ 模块,可以导入__main__。例如,以下将插入 x__main__ 模块中:

    boost::python::import("__main__").attr("x") = ...;
    

这是一个例子 demonstrating如何直接从 C++ 构建 Python 对象,将 C++ 对象的所有权转移给 Python,以及构建引用 C++ 对象的 Python 对象:

#include <iostream>
#include <boost/python.hpp>

// Mockup model.
struct spam
{
  spam(int id)
    : id_(id)
  {
    std::cout << "spam(" << id_ << "): "  << this << std::endl;
  }

  ~spam()
  {
    std::cout << "~spam(" << id_ << "): " << this << std::endl;
  }

  // Explicitly disable copying.
  spam(const spam&) = delete;
  spam& operator=(const spam&) = delete;

  int id_;
};

/// @brief Transfer ownership to a Python object.  If the transfer fails,
///        then object will be destroyed and an exception is thrown.
template <typename T>
boost::python::object transfer_to_python(T* t)
{
  // Transfer ownership to a smart pointer, allowing for proper cleanup
  // incase Boost.Python throws.
  std::unique_ptr<T> ptr(t);

  // Use the manage_new_object generator to transfer ownership to Python.
  namespace python = boost::python;
  typename python::manage_new_object::apply<T*>::type converter;

  // Transfer ownership to the Python handler and release ownership
  // from C++.
  python::handle<> handle(converter(*ptr));
  ptr.release();

  return python::object(handle);
}

namespace {
spam* global_spam;
} // namespace

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  // Expose spam.
  auto py_spam_type = python::class_<spam, boost::noncopyable>(
      "Spam", python::init<int>())
    .def_readonly("id", &spam::id_)
    ;

  // Directly create an instance of Python Spam and insert it into this
  // module's namespace.
  python::scope().attr("spam1") = py_spam_type(1);

  // Construct of an instance of Python Spam from C++ spam, transfering
  // ownership to Python.  The Python Spam instance will be inserted into
  // this module's namespace.
  python::scope().attr("spam2") = transfer_to_python(new spam(2));

  // Construct an instance of Python Spam from C++, but retain ownership of
  // spam in C++.  The Python Spam instance will be inserted into the
  // __main__ scope.
  global_spam = new spam(3);
  python::import("__main__").attr("spam3") = python::ptr(global_spam);
}

交互使用:

>>> import example
spam(1): 0x1884d40
spam(2): 0x1831750
spam(3): 0x183bd00
>>> assert(1 == example.spam1.id)
>>> assert(2 == example.spam2.id)
>>> assert(3 == spam3.id)
~spam(1): 0x1884d40
~spam(2): 0x1831750

在示例用法中,请注意 Python 如何在退出时不销毁 spam(3),因为它没有被授予底层对象的所有权。

关于python - 使用 boost-python 将 python 变量设置为 C++ 对象指针,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33877467/

相关文章:

python - CPU 密集型代码在笔记本电脑上的运行速度是台式机的两倍

python - 使用 Python 时如何在 Google Colab 中引用文件?

python - 正则表达式替换 w 匹配

c++ - 为什么我的 C++ MPI 代码卡住了?

boost 多精度 cpp_dec_float 仅与所需精度进行比较

python - 从python使用IE下载文件

c++ - 在 C++ 中删除多维结构会导致访问冲突

c++ - 使用 boost::asio 打洞

c++ - Boost::filesystem::is_empty() 为符号链接(symbolic link)返回 false

c++ - 从原始指针创建 weak_ptr<>