创建嵌套命名空间的boost-python

6
使用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")
        ...
    ;
    }
}

它会导致编译时错误: 链接规范必须在全局范围内

是否有一种声明B类的方式,以便从Python中访问为a.b.B


1
我把这个放在注释里,因为我从来没有尝试过:http://goo.gl/FxUHE - Matthew Scouten
@Matthew - 谢谢,无论如何使用PyImport_AddModule都是一个好方法,这就是为什么+1。 - Dewfy
2个回答

12
你需要的是一个boost::python::scope。Python没有'namespaces'的概念,但你可以使用类作为命名空间:
#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", &a::A::method)
        ;

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

    class_<a::b::B>("B")
        //.def("somemethod", &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

所有的aa.Aa.ba.b.B实际上都是类,但您可以将aa.b视为命名空间 - 并且从未实例化它们。


1
当我尝试这个时,我感到非常惊喜 - 我实际上并没有期望嵌套作用域能够工作!Boost Python 有时真的非常棒。 - James
如果我想要 mylib.amylib.a.Amylib.bmylib.b.B,我该怎么办?我如何“退出”“a”作用域? - robert
7
boost::python::scope对象使用RAII技术,因此添加额外的{}可以改变该作用域对象的生命周期;当作用域对象被销毁时,它会恢复创建时存在的命名空间。 - James
@Autopulated:您的构造方式与文档中不同。根据文档,作用域对象将使用任意名称进行赋值创建。然后使用封闭类名称创建子类包装器的名称。而您做的是创建一个命名空间,然后使用相同名称创建一个作用域对象,最后在定义子类包装器时使用该命名空间/作用域对象名称,即 class_<a::A>。您能解释一下这样做的原理吗? - Faheem Mitha
@FaheemMitha:因为我不知道那个构造函数存在!(而且我在文档中没有看到它)使用类反映了Python的工作方式,所以这是我尝试的唯一方法。 - James
显示剩余10条评论

10

虚拟类的技巧相当好,但是不允许:

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

因此,使用PyImport_AddModule()代替。您可以在以下文章中找到完整的特色示例:Python扩展模块中的软件包,作者是Vadim Macagon。

简而言之:

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")...

2
上面詹姆斯的回答不允许 import mylib.a 的要点非常重要。读者请注意! - ofloveandhate

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接