boost.python caching wrapped class members

拈花ヽ惹草 提交于 2019-12-11 23:18:14

问题


I have a trivial classes dependency:

class A {
    ... // constructor is omitted 
public:
    const std::string str1;
};
class B {
public:
    std::shared_ptr<A> a;
}

BOOST_PYTHON_IMPORT(wrapped) {

    class_<A, std::shared_ptr<A>>("APy")
    .def_readonly("str1", &A::str1);

    class_<B>("BPy")
    .def_readwrite("a", &B::a);
}

In Python

import wrapped as wr
b = wr.BPy()
s1 = b.a.str1 // APy wrapper created
s2 = b.a.str1 // new APy wrapper created even though object is the same

Is there some way to create this APy wrapper once for an object? Especially, because inner object A is immutable(in this particular case). Otherwise, there is considerable overhead of creating lots of such temporary objects.


回答1:


The APy wrappers are temporaries because s1, s2 are strings. Once s1 is created, Python doesn't care if the setup that created it could also be used to create s2. Most likely b.a gets discarded because it isn't stored. Does the same thing happen when you do something like

a1 = b.a
s1 = a1.str1
s2 = a1.str1

?

Update:

We're trying to find out what b.a actually is in Python.

Your invocation is

BOOST_PYTHON_IMPORT(wrapped) {

    class_<A, std::shared_ptr<A>>("APy")
    .def_readonly("str1", &A::str1);

    class_<B>("BPy")
    .def_readwrite("a", &B::a);
}

The definition of def_readwrite in boost/python/class.hpp is

template <class D>
self& def_readwrite(char const* name, D const& d, char const* doc=0)
{
    return this->def_readwrite_impl(name, d, doc BOOST_PYTHON_DATA_MEMBER_HELPER(D));
}
// translates to
class_<B>& def_readwrite(char const* name, A &d,
  char const* doc=0, detail::is_data_member_pointer<B>()){...}

where the best matching implementation of def_readwrite_impl is

class_<B>& def_readwrite_impl(char const* name, A B::*a,
  char const* doc, mpl::true_) 

because B::*a should be a member of B but not a function pointer. That in turn invokes

class_<B>& def_readwrite_impl(char const* name, A B::*pm_, char const* doc, mpl::true_)

pm_ is an unbound pointer to some object of type B's a member. Now, let's move on to add_property.

class_<B>& add_property(char const* name, A &fget = B::*a,
  A &fset = B::*a, char const* docstr = 0)

From here we go to boost/python/objects/class.hpp and look at class_base::add_property:

void add_property(char const* name, 
    object const& fget, object const& fset, char const* docstr);

Implementation is unfortunately hidden. But the signature shows that the magic happens in make_getter.

template <class F>
object make_getter(F f)
{
    typedef typename api::is_object_operators<F>::type is_obj_or_proxy;

    return this->make_fn_impl(
        detail::unwrap_wrapper((W*)0)
      , f, is_obj_or_proxy(), (char*)0, detail::is_data_member_pointer<F>()
    );
}

unwrap_wrapper is not doing anything to the pointer, because std::shared_ptr doesn't derive from boost::python::wrapper. is_data_member_pointer was already part of the first macro. I'm not sure if this is the broken part in your case because at some point digging for more decorators became really tedious.

Looking for some decorator definitions I stumbled upon bad news. Added it as a comment to your original question.



来源:https://stackoverflow.com/questions/38826816/boost-python-caching-wrapped-class-members

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!