#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
, очень важен. читатель, обратите внимание!