boost python返回与make_constructor相同的实例 [英] boost python return same instance with make_constructor

查看:237
本文介绍了boost python返回与make_constructor相同的实例的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图让这个代码在init函数和回调函数中返回相同的实例



test1.py



  import test1 

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

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

test1.register_callback(func)



test1.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() 知道这个第一个参数,但没有自定义点来转发参数到包装功能。一个解决方案是将 __ init __ boost :: python :: make_function()包括 self ,然后委托给从 boost :: python :: make_constructor()返回的函子$ c>:

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

void create(boost :: python :: object self)
{
//创建一个构造函数对象。在这种情况下,正在使用lambda
//投射到函数。
auto constructor = boost :: python :: make_constructor(+ [](){
return boost :: make_shared< C>();
});

//调用构造函数。
constructor(self);

//如果构造不抛出,则存储对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))
;

...
}





b $ b

这是一个完整的示例演示此方法:

  #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)
{
//创建一个构造函数对象。
auto constructor = boost :: python :: make_constructor(
+ [](Args& ... args){
return boost :: make_shared< C>(std :: forward< ; Args(args)...);
});

//调用构造函数。
constructor(self,std :: forward< Args>(args)...);

//如果构造不抛出,则存储对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);
}

互动用法:



< pre class =lang-python prettyprint-override> >>> 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)


I'm trying to make so this code returns the same instance in both the init function and the callback function

test1.py

import test1

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

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

test1.register_callback(func)

test1.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);
}

The output I get now is:

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

And what I'm trying to get is:

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

is this possible and how?

解决方案

When Python constructs an object, the __init__ will be invoked with the first argument representing the object being constructed, often called self. Boost.Python tries to hide this argument as much as possible, only exposing it to an init-expression under certain conditions. The callable Python object returned from boost::python::make_constructor() is aware of this first argument, but there are no customization points to have it forward the argument to wrapped function. One solution is to expose a C++ function as __init__ with boost::python::make_function() that accepts all of the arguments to be provided from Python, including self, then delegate to the functor returned from 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))
    ;

  ...
}


Here is a complete example demonstrating this approach:

#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);
}

Interactive usage:

>>> 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)

这篇关于boost python返回与make_constructor相同的实例的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆