c++ - boost python 返回与 make_constructor 相同的实例

标签 c++ python-2.7 c++11 boost-python

我正在尝试让这段代码在初始化函数和回调函数中返回相同的实例

测试1.py

import test1

c = test1.C()
print 'init:', c

def func(c):
    print 'func:', c

test1.register_callback(func)

测试1.cpp

#include <iostream>
#include <vector>

#include <boost/python.hpp>

using namespace boost::python;

class C;
std::vector<boost::shared_ptr<C>> v;

class C
: public boost::noncopyable
{
public:
    C() {
        std::cout << "C()" << std::endl;
    }

    ~C() {
        std::cout << "~C()" << std::endl;
    }
};

boost::shared_ptr<C> create() {
    C *c = new C();
    auto ptr = boost::shared_ptr<C>(c);
    v.push_back(ptr);
    return ptr;
}

void register_callback(object func) {
    func(v[0]);
}

BOOST_PYTHON_MODULE(test1)
{
    class_<C, boost::shared_ptr<C>, boost::noncopyable>("C", no_init)
        .def("__init__", make_constructor(&create))
    ;

    def("register_callback", register_callback);
}

我现在得到的输出是:

init: <test1.C object at 0x7f62181bd5d0>
func: <test1.C object at 0x7f62181c1848>

我想得到的是:

init: <test1.C object at 0x7f62181bd5d0>
func: <test1.C object at 0x7f62181bd5d0>

这可能吗?如何实现?

最佳答案

当 Python 构造一个对象时,__init__将使用表示正在构造的对象的第一个参数调用,通常称为 self . Boost.Python 试图尽可能地隐藏这个参数,只将它暴露给 init-expression。在某些条件下。从 boost::python::make_constructor() 返回的可调用 Python 对象知道第一个参数,但没有自定义点可以将参数转发给包装函数。一种解决方案是将 C++ 函数公开为 __init__boost::python::make_function()接受 Python 提供的所有参数,包括 self , 然后委托(delegate)给从 boost::python::make_constructor() 返回的仿函数:

...
std::vector<boost::python::object> v;

void create(boost::python::object self)
{
  // Create a constructor object.  In this case, a lambda
  // casted to a function is being used.
  auto constructor = boost::python::make_constructor(+[]() {
    return boost::make_shared<C>();
  });

  // Invoke the constructor.
  constructor(self);

  // If construction does not throw, then store a reference to self.
  v.push_back(self);
}

...

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<C, boost::shared_ptr<C>, boost::noncopyable>(
      "C", python::no_init)
    .def("__init__", python::make_function(&create))
    ;

  ...
}

这是一个完整的例子demonstrating这种方法:

#include <boost/python.hpp>
#include <vector>
#include <boost/make_shared.hpp>

class C: public boost::noncopyable {};
std::vector<boost::python::object> v;

template <typename ...Args>
void create(boost::python::object self, Args&&... args)
{
  // Create a constructor object.
  auto constructor = boost::python::make_constructor(
    +[](Args&&...args) {
    return boost::make_shared<C>(std::forward<Args>(args)...);
  });

  // Invoke the constructor.
  constructor(self, std::forward<Args>(args)...);

  // If construction does not throw, then store a reference to self.
  v.push_back(self);
}

void register_callback(boost::python::object func)
{
  func(v[0]);
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<C, boost::shared_ptr<C>, boost::noncopyable>(
      "C", python::no_init)
    .def("__init__", python::make_function(&create<>))
    ;

  python::def("register_callback", &register_callback);
}

交互使用:

>>> import example
>>> c1 = example.C()
>>> print 'init:', c1
init: <example.C object at 0x7f12f425d0a8>
>>> c2 = None
>>> def func(c):
...     global c2
...     print 'func:', c
...     c2 = c
...
>>> example.register_callback(func)
func: <example.C object at 0x7f12f425d0a8>
>>> assert(c1 is c2)

关于c++ - boost python 返回与 make_constructor 相同的实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36200333/

相关文章:

python - 解析并获取日志文件中两个时间对象之间的值

c++ - is_convertible 用于多个参数

c++ - 在 C++ 的宽松内存模型中是否存在依赖循环的非因果行为?

c++ - 是否可以强制父类(super class)中的非 const 虚方法优先于子类中同名的 const 方法?

c++ - Boost::log:基于级别的不同格式(HTML 格式)

python - json 存储未正确更新值 kivy

python - 为什么我得到 "ق"而不是 "fi"?

C++ "vector iterator not decrementable"?

c++ - 读取文件和未定义的行为

c++ - __int128 @ 最小负值的 UDL(用户定义文字)整数溢出