создать boost-вложенное пространство имен python

#python #boost #boost-python

#python #boost #boost-python

Вопрос:

Используя boost python, мне нужно создать вложенное пространство имен.

Предположим, у меня есть следующая структура класса cpp:

 namespace a
{
    class A{...}
    namespace b
    {
         class B{...}
    }
}
  

Очевидное решение не работает:

 BOOST_PYTHON_MODULE( a ) {
    boost::python::class_<a::A>("A")
     ...
    ;
    BOOST_PYTHON_MODULE(b){
        boost::python::class_<a::b::B>("B")
        ...
    ;
    }
}
  

Это вызывает ошибку времени компиляции: linkage specification must be at global scope

Есть ли какой-либо способ объявить класс B, к которому можно было бы получить доступ из Python как a.b.B ?

Комментарии:

1. Я поместил это в комментарий, потому что я никогда не пробовал это: goo.gl/FxUHE

2. @Matthew — спасибо, в любом случае использование PyImport_AddModule — хороший способ, поэтому 1

Ответ №1:

Что вам нужно, так это boost::python::scope .

В Python нет понятия «пространства имен», но вы можете использовать класс, очень похожий на пространство имен:

 #include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include <boost/python/scope.hpp>
using namespace boost::python;

namespace a
{
    class A{};

    namespace b
    {
         class B{};
    }
}

class DummyA{};
class DummyB{};

BOOST_PYTHON_MODULE(mymodule)
{
    // Change the current scope 
    scope a
        = class_<DummyA>("a")
        ;

    // Define a class A in the current scope, a
    class_<a::A>("A")
        //.def("somemethod", amp;a::A::method)
        ;

    // Change the scope again, a.b:
    scope b
        = class_<DummyB>("b")
        ;

    class_<a::b::B>("B")
        //.def("somemethod", amp;a::b::B::method)
        ;
}
  

Затем в python у вас есть:

 #!/usr/bin/env python
import mylib

print mylib.a,
print mylib.a.A
print mylib.a.b
print mylib.a.b.B
  

Все a , a.A , a.b и a.b.B на самом деле являются классами, но вы можете обрабатывать a и a.b точно так же, как пространства имен, и никогда не создавать их экземпляры

Комментарии:

1. Я был приятно удивлен, когда попробовал это — на самом деле я не ожидал, что области вложенности будут работать! Boost python действительно иногда очень аккуратен.

2. Что, если я хочу mylib.a , mylib.a.A , mylib.b , и mylib.b.B ? Как мне «выйти» из области «a»?

3. @robert boost::объекты python::scope используют RAII, поэтому добавьте дополнительный {}, чтобы изменить время жизни объектов области; когда объект области уничтожается, он восстанавливает пространство имен, которое присутствовало при его создании.

4. @Autopulated: ваша конструкция отличается от конструкции в документах. В документах объект области создается при назначении с произвольным именем. Тогда имя, используемое для создания оболочки подкласса, является именем заключающего класса. Что вы делаете, это создаете пространство имен, а затем создаете объект области видимости с тем же именем, а затем используете это пространство имен / имя объекта области видимости при определении оболочки для подкласса, т.Е. class_<a::A> . Можете ли вы объяснить обоснование этого?

5. @FaheemMitha: Потому что я не знал, что конструктор существует! (И я не вижу этого в документации? ) Использование классов отражает то, как оно работает в python, так что это единственный способ, который я когда-либо пробовал.

Ответ №2:

Трюк с фиктивными классами довольно хорош, но не позволяет:

 import mylib.a
from mylib.a.b import B
  

Итак, вместо этого используйте PyImport_AddModule() . Вы можете найти полнофункциональные примеры в следующей статье: Пакеты в модулях расширения Python, Вадим Макагон.

Короче говоря:

 namespace py = boost::python;
std::string nested_name = py::extract<std::string>(py::scope().attr("__name__")   ".nested");
py::object nested_module(py::handle<>(py::borrowed(PyImport_AddModule(nested_name.c_str()))));
py::scope().attr("nested") = nested_module;
py::scope parent = nested_module;
py::class_<a::A>("A")...
  

Комментарии:

1. пункт, который не допускает приведенный выше ответ Джеймса import mylib.a , очень важен. читатель, обратите внимание!