提升 python return 与 make_constructor 相同的实例
boost python return same instance with make_constructor
我正在努力使这段代码 returns 在初始化函数和回调函数中成为同一个实例
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>
这可能吗?如何实现?
它已经是相同 shared_ptr<C>
中的相同 C
实例。你可以很容易地验证这一点。
问题是您要基于此 shared_ptr<C>
创建两个不同的 py::object
:一个来自 create()
,一个来自 register_callback()
。这些必然是不同的对象,它们彼此无关。
简单的解决方案就是不使用 make_constructor
。创建工厂函数:
py::object makeC() {
C *c = new C();
auto ptr = py::object{boost::shared_ptr<C>(c)};
v.push_back(ptr); // store as objects, since you need them to be the same
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)
/* actually no_init for real */
;
def("makeC", makeC);
def("register_callback", register_callback);
}
当Python构造一个对象时,__init__
将被调用,第一个参数表示正在构造的对象,通常称为self
。 Boost.Python 试图尽可能地隐藏这个参数,只有将它暴露给 init-expression under certain conditions. The callable Python object returned from boost::python::make_constructor()
才知道第一个参数,但是没有定制点让它将参数转发给包装函数。一种解决方案是将 C++ 函数公开为 __init__
和 boost::python::make_function()
,它接受从 Python 提供的所有参数,包括 self
,然后委托给从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", ®ister_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)
我正在努力使这段代码 returns 在初始化函数和回调函数中成为同一个实例
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>
这可能吗?如何实现?
它已经是相同 shared_ptr<C>
中的相同 C
实例。你可以很容易地验证这一点。
问题是您要基于此 shared_ptr<C>
创建两个不同的 py::object
:一个来自 create()
,一个来自 register_callback()
。这些必然是不同的对象,它们彼此无关。
简单的解决方案就是不使用 make_constructor
。创建工厂函数:
py::object makeC() {
C *c = new C();
auto ptr = py::object{boost::shared_ptr<C>(c)};
v.push_back(ptr); // store as objects, since you need them to be the same
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)
/* actually no_init for real */
;
def("makeC", makeC);
def("register_callback", register_callback);
}
当Python构造一个对象时,__init__
将被调用,第一个参数表示正在构造的对象,通常称为self
。 Boost.Python 试图尽可能地隐藏这个参数,只有将它暴露给 init-expression under certain conditions. The callable Python object returned from boost::python::make_constructor()
才知道第一个参数,但是没有定制点让它将参数转发给包装函数。一种解决方案是将 C++ 函数公开为 __init__
和 boost::python::make_function()
,它接受从 Python 提供的所有参数,包括 self
,然后委托给从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", ®ister_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)