boost python返回与make_constructor相同的实例 [英] boost python return same instance with 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>返回的函子$ 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", ®ister_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屋!