Boost(8):Boost.Python 实现 Python 对象以及各种类型的内置操作和方法

说明

Python 有多种非常好用的数据类型,如 Numbers,String,List,Tuple,Dictionary 和 Set。在前面的示例中我们经常用到的 Numbers 和 String(它们的内容) 可以直接在 C++ 代码中使用,因为这两者也是 C++ 的数据类型(虽然实现上不同,但不妨碍两者通用)。但是其他类型的数据结构在 C++ 中并没有,那么当 Python 需要使用这些类型且与 C++ 代码有交互时,该如何处理呢?

在 Boost.Python 和 C++ 的观点中,这些 Pythonic 变量只是类对象的实例。Python 的每一个变量或方法都是一个 Python 对象,这些都具备各种属性,且 Python 赋予了这些对象这样或那样的内置方法,以使我们可以方便地使用它们。Boost.Python 库提供了一个名为 object 的类,它可以封装一个有效的 Python 对象并提供了一个与 Python 类似的接口。换言之,每一个 Python 对象可以作为 Boost.Python 的一个 object 类实例,同时 Boost.Python 提供了这个实例接近 Python 语法的操作的支持,这些支持主要以运算符重载的形式实现。比如:

PythonC++说明
y = x.fooy = x.attr(“foo”);获取 x 的属性值,通常是成员变量
x.foo = 1x.attr(“foo”) = 1;设置 x 的属性
y = x[z]y = x[z];列表/字典操作
x[z] = 1x[z] = 1;列表/字典操作
y = x[3:-1]y = x.slice(3,-1);切片操作
y = x[3:]y = x.slice(3,_);
y = x[:-2]y = x.slice(_,-2);
z = x(1, y)z = x(1, y);调用函数
z = x.f(1, y)z = x.attr(“f”)(1, y);调用成员函数
not x!x逻辑非
x and yx && y逻辑与

Boost.Python 的目标之一是提供 C++ 和 Python 之间的双向映射,同时保持 Python 的感觉。 Boost.Python C++ 对象尽可能接近 Python。在上表的操作示例中,虽然不完全一致,但是 Boost.Python 尽量提供了符合 C++ 语法又与 Python 功能一致的功能。

上述 Python 数据类型,除 Set 外,Boost.Python 都将其视为一个类的实例。如何理解呢,比如一个 Python 变量 a = [1,2,3,4] 是一个 List 类型,那么在 Boost.Python 中 a 是一个 class list 实例。

Object 类是一个基类,提供了针对所有Python 对象的通用的操作方法,对于 Python 的常用的数据类型,Boost.Python 提供了基于 object 的与 Python 类型对应的派生类:

  • list
  • dict
  • tuple
  • str
  • long_
  • enum

注:目前不包含 Set 类型。

这些派生类与基类的关系如下图:
在这里插入图片描述
针对 Python 对象的封装,Boost.Python 提出了两个封装概念: ObjectWrapper 和 TypeWrapper,前者用于描述管理 Python 的对象,后者针对特定的 Python 对象进行优化和改进。

ObjectWrapper

ObjectWrapper 定义了两个概念,用于描述管理 Python 地向的类,并且旨在支持使用类似 Python 的语法。

ObjectWrapper 概念的模型将 object 作为公用基类并用于通过成员函数提供特殊的构造函数或其他功能。除非返回类型 R 本身是一个 TypeWrapper,否则它是形式的成员函数调用。
比如语句

x.some_function(a1, a2,...an)

等价于:

extract<R>(x.attr("some_function")(object(a1), object(a2),...object(an)))()


TypeWrapper

TypeWrapper 是对 ObjectWrapper 的改进,它与特定的 Python 类型 X 相关联。对于给定的 TypeWrapper T,有效的构造函数表达式为:

T(a1, a2,...an)

构建一个新的 T 对象,管理调用 X 的结果,参数对应于:

object(a1), object(a2),...object(an)

当用作封装 C++ 函数的参数或用作 extract<> 的模板参数时,只有关联 Python 类型的实例才会被视为匹配项。

警告

当返回类型为 TypeWrapper 时,特殊成员函数调用的结果是返回的对象可能与特定 Python 对象的类型不匹配,通常情况下这不是一个严重的问题;最坏的结果是在运行时检测到错误的时间会比其他情况稍晚一些。有关如何发生这种情况的示例,请注意 dict 成员函数 items 返回列表类型的对象。现在假设用户在 Python 中定义了这个 dict 子类:

>>> class mydict(dict):
...     def items(self):
...         return tuple(dict.items(self)) # return a tuple

由于 mydict 的实例是 dict 的实例,因此当用作包装 C++ 函数的参数时,boost::python::dict 可以接受 Python 类型 mydict 的对象。在这个对象上调用 items() 可以导致 boost::python::list 的实例,它实际上包含一个 Python 元组。随后尝试在此对象上使用列表方法(例如追加或任何其他变异操作)将引发与尝试从 Python 执行此操作时发生的相同异常。

Object 基类

Object 类是通用 Python 对象的封装类和其他 TypeWrapper 类的基类。object 有一个模板化的构造函数,可以使用与 call<> 的参数相同的底层机制将任何 C++ 对象转换为 Python。如果一个对象实例是在没有任何构造函数参数的情况下创建的,那么这个实例的值就是 None。

object 类封装 PyObject*。处理 PyObjects 的所有复杂性,例如管理引用计数,都由对象类处理。Boost.Python C++ 对象实际上可以从任何 C++ 对象显式构造。

先看一个简单的示例,这个 Python 代码片段:

def f(x, y):
     if (y == 'foo'):
         x[3:7] = 'bar'
     else:
         x.items += y(3, x)
     return x

def getfunc():
   return f;

可以通过以下方式使用 Boost.Python 工具在 C++ 中重写:

object f(object x, object y) {
     if (y == "foo")
         x.slice(3,7) = "bar";
     else
         x.attr("items") += y(3, x);
     return x;
}
object getfunc() {
    return object(f);
}

除了由于我们使用 C++ 编写代码而导致的外观差异之外,Python 编码人员应该立即明白外观和有熟悉的感觉。

Object 类提供了诸如切片,属性策略和操作符等功能的应用,详细内容参见:boost/python/object.hpp

Object 派生类

Object 派生类也就是前面提到的 TypeWrapper 的行为类似于真正的 Python 类型。例如:

str(1) ==> "1"

在适当的情况下,特定的派生对象具有相应的 Python 类型的方法。例如, dict 有一个 keys() 方法:

d.keys()

make_tuple 用于声明元组。例子:

make_tuple(123, 'D', "Hello, World", 0.0);

在 C++ 中,当 Boost.Python 对象用作函数的参数时,需要进行子类型匹配。例如,当如下声明的函数 f 被包装时,它将只接受 Python 的 str 类型和子类型的实例。

void f(str name)
{
    object n2 = name.attr("upper")();   // NAME = name.upper()
    str NAME = name.upper();            // better
    object msg = "%s is bigger than %s" % make_tuple(NAME,name);
}

更详细地说:

str NAME = name.upper();

说明我们提供 str 类型方法的版本作为 C++ 成员函数。

object msg = "%s is bigger than %s" % make_tuple(NAME,name);

说明我们可以在 Python 中编写与 “format” % x,y,z 等效的 C++,这很有用,因为在标准 C++ 中没有简单的方法可以做到这一点。

但是需要注意的是:大多数情况下,Python 和 C++ 之间的对象是拷贝过来的,如果修改某一个对象不会影响到另一个对象的值。

# Python:
>>> d = dict(x.__dict__)     # copies x.__dict__
>>> d['whatever'] = 3        # modifies the copy

// C++ 
dict d(x.attr("__dict__"));  // copies x.__dict__
d['whatever'] = 3;           // modifies the copy


class_ as objects

由于 Boost.Python 对象的动态特性,任何 class_ 也可能是这些类型之一!我们可以使用它来创建包装实例。例子:

object vec345 = (
    class_<Vec2>("Vec2", init<double, double>())
        .def_readonly("length", &Point::length)
        .def_readonly("angle", &Point::angle)
    )(3.0, 4.0);

assert(vec345.attr("length") == 5.0);


Creating boost::python::object from PyObject*

当我们希望 boost::python::object 管理指向 PyObject* pyobj 的指针时,可以:

boost::python::object o(boost::python::handle<>(pyobj));

在这种情况下,o 对象管理 pyobj,它不会增加构造时的引用计数。

否则,要参考使用 boost::python::borrowed

boost::python::object o(boost::python::handle<>(boost::python::borrowed(pyobj)));

在这种情况下,调用 Py_INCREF,因此当对象 o 超出范围时,pyobj 不会被破坏。

list class

暴露 Python 内置的列表类型的方法。下面定义的构造函数和成员函数的语义可以通过阅读 TypeWrapper 概念定义来完全理解。由于 list 是从 object 公开派生的,因此 public object 接口也适用于 list 实例。

该类定义在 <boost/python/list.hpp> 头文件中,部分代码 如下:

namespace boost { namespace python
{
  class list : public object
  {
   public:
      // 构造函数,生成一个 list 类实例
      list(); // new list
      template <class T>
      explicit list(T const& sequence);

      template <class T>
      void append(T const& x);    // 在列表末尾添加新的对象

      template <class T>
      long count(T const& value) const;   // 在列表末尾添加新的对象

      template <class T>
      void extend(T const& x);            // 在列表末尾一次性追加另一个序列中的多个值

      template <class T>
      long index(T const& x) const;     // 从列表中找出某个值第一个匹配项的索引位置

      template <class T>
      void insert(object const& index, T const& x); // insert object before index

      object pop(); // remove and return item at index (default last)
      object pop(long index);
      object pop(object const& index);

      template <class T>
      void remove(T const& value);       // 移除列表中 value 的第一个匹配项

      void reverse(); // reverse *IN PLACE*

      void sort(); //  sort *IN PLACE*; if given, cmpfunc(x, y) -> -1, 0, 1
      template <class T>
      void sort(T const& value);
  };
}}

Python list 支持的大部分方法在 Boost.Python list class 中都有实现,且为了尽量与 python 的习惯一致,函数调用方式和参数也都类似。

示例
下面以简单的 reverse() 函数为例,介绍 Boost.Python 的 list 类的使用
C++:

#include <iostream>

#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
#include <boost/python/return_by_value.hpp>
#include <boost/python/return_value_policy.hpp>

#include <boost/python/list.hpp>

namespace bp = boost::python;

bp::list list_reverse (bp::list &l1)
{
    std::cout << "Input list length: " << len(l1) << std::endl;

    l1.reverse();

    return l1;
}

BOOST_PYTHON_MODULE(objects)
{
    using namespace boost::python;

    def("list_reverse", list_reverse, args("l1"), return_value_policy<return_by_value>())
    ;
}

Python:

$ python
>>> import objects
>>> a = [1, 3, 6, 2, 9, 0]
>>> objects.list_reverse(a)
Input list length: 6
[0, 9, 2, 6, 3, 1]

好吧,这个示例很无聊,主要目的是说明当 python 接口传入一个 list 参数时,C++ 可以通过 Boost.Python 实现对该参数的处理。

dict class

dict 类是针对 python 字典数据类型封装的 object 衍生类,提供了 python dict 类似的方法和操作。定义在文件 <boost/python/dict.hpp> 中。

namespace boost { namespace python
{
   class dict : public object
   {
      dict();    // 构造函数
      template< class T >
      dict(T const & data);

      // modifiers
      void clear();     // 删除字典内所有元素
      dict copy();      // 返回一个字典的浅复制

      template <class T1, class T2>
      tuple popitem();  // 返回并删除字典中的最后一对键和值。

      // 和get()类似, 但如果键 k 不存在于字典中,将会添加键并将值设为 d 或者 default
      template <class T>
      object setdefault(T const &k);    
      template <class T1, class T2>
      object setdefault(T1 const & k, T2 const & d);

      // 把字典 E 的键/值对更新到dict里
      void update(object_cref E);
      template< class T >
      void update(T const & E);

      // 返回字典的所有值
      list values() const;

      // 返回指定键k的值,如果键不在字典中返回 d 或者默认值 NULL
      object get(object_cref k) const;
      template<class T>
      object get(T const & k) const;
      object get(object_cref k, object_cref d) const;
      object get(T1 const & k, T2 const & d) const;

      // 如果键在字典dict里返回true,否则返回false
      bool has_key(object_cref k) const;
      template< class T >
      bool has_key(T const & k) const;

      list items() const;         // 以列表返回字典的元组对象
      object iteritems() const;   // 以迭代器的形式返回字典元组
      object iterkeys() const;    // 以迭代器的形式返回字典关键字
      object itervalues() const;  // 以迭代器的形式返回字典值
      list keys() const;          // 返回字典的关键字列表
  };
}}

示例
C++:

bp::dict swap_object_dict(bp::object target, bp::dict d)
{
    bp::dict result = bp::extract<bp::dict>(target.attr("__dict__"));
    target.attr("__dict__") = d;
    
    return result;
}

这个函数会将输入参数中的字典 d 的内容和 target 的 __dict__ 属性互换,并将 target 的原有 __dict__ 属性作为新的字典输出。

Python:

import objects

class O1:
    ''' class O1 '''
    Name = 'Test'
    Age = 0

    def __init__(self):
        self.Name = 'Test'
        self.Age = 0

a = O1()
print(a.__dict__)

d1 = {"Name":"Xiangdi", "Age":10}
print(d1)

d2 = objects.swap_object_dict(a, d1)
print(a.__dict__)
print(d2)

运行结果:

$ python objects.py
{'Na': 'Test', 'Ag': 0}
{'Name': 'Xiangdi', 'Age': 10}
{'Name': 'Xiangdi', 'Age': 10}
{'Na': 'Test', 'Ag': 0}


tuple class

这个类封装了部分类似 Python tuple 数据类型的功能。但是相对于其他衍生类, class tuple 的函数相对较少,只有一个构造函数。特点在于提供了多种构造 tuple 的重载函数 make_tuple。其定义在 <boost/python/tuple.hpp> 中。

namespace boost { namespace python
{
   class tuple : public object
   {
      // tuple() -> an empty tuple
      tuple();

      // tuple(sequence) -> tuple initialized from sequence's items
      template <class T>
      explicit tuple(T const& sequence)
  };
}}

namespace boost { namespace python
{
  tuple make_tuple();

  template <class A0>
  tuple make_tuple(A0 const& a0);

  template <class A0, class A1>
  tuple make_tuple(A0 const& a0, A1 const& a1);
  ...
  template <class A0, class A1,...class An>
  tuple make_tuple(A0 const& a0, A1 const& a1,...An const& an);
}}

示例
C++:

bp::tuple head_and_tail_tuple (bp::object seq)
{
    return bp::make_tuple(seq[0],seq[-1]);
}

Python:

$ python
>>> import objects
>>> t1 = ("Ali", "Baidu", "Tencent", "Google")
>>> t2 = objects.head_and_tail_tuple(t1)
>>> print(t2)
('Ali', 'Google')


str class

str class 模拟了 Python 内置 str 类型的字符串方法。定义在 <boost/python/str.hpp> 中,其提供的函数如下:

namespace boost { namespace python
{
  class str : public object
  {
   public:
      // 构造函数
      str(); // new str
      str(char const* s); // new str
      str(char const* start, char const* finish); // new str
      str(char const* start, std::size_t length); // new str
      template <class T>
      explicit str(T const& other);

      // 将字符串的第一个字符转换为大写
      str capitalize() const;

      // 返回一个指定的宽度 width 居中的字符串
      template <class T>
      str center(T const& width) const;

      // 返回 sub 出现的次数,start 和 end表示指定的范围
      template<class T>
      long count(T const& sub) const;
      template<class T1, class T2>
      long count(T1 const& sub,T2 const& start) const;
      template<class T1, class T2, class T3>
      long count(T1 const& sub,T2 const& start, T3 const& end) const;

      // 对 str 进行解码
      object decode() const;
      template<class T>
      object decode(T const& encoding) const;
      template<class T1, class T2>
      object decode(T1 const& encoding, T2 const& errors) const;

      // 对 str 进行编码
      object encode() const;
      template <class T>
      object encode(T const& encoding) const;
      template <class T1, class T2>
      object encode(T1 const& encoding, T2 const& errors) const;

      // 检查字符串是否以 suffix 结束,其中 start 和 end 表示字符串范围
      template <class T>
      bool endswith(T const& suffix) const;
      template <class T1, class T2>
      bool endswith(T1 const& suffix, T2 const& start) const;
      template <class T1, class T2, class T3>
      bool endswith(T1 const& suffix, T2 const& start, T3 const& end) const;

      // 把字符串中的 tab 符号转为空格,tabsize 表示空格数,默认为8
      str expandtabs() const;
      template <class T>
      str expandtabs(T const& tabsize) const;

      // 从字符串中查找 sub 子串,其中 start 和 end 表示字符串范围
      template <class T>
      long find(T const& sub) const;
      template <class T1, class T2>
      long find(T1 const& sub, T2 const& start) const;
      template <class T1, class T2, class T3>
      long find(T1 const& sub, T2 const& start, T3 const& end) const;

      // 跟find()方法一样,只不过如果 sub 不在字符串中会报一个异常。
      template <class T>
      long index(T const& sub) const;
      template <class T1, class T2>
      long index(T1 const& sub, T2 const& start) const;
      template <class T1, class T2, class T3>
      long index(T1 const& sub, T2 const& start, T3 const& end) const;

      // 如果字符串 [...] 则返回 True, 否则返回 False
      bool isalnum() const;    // [至少有一个字符且所有字符都是字母或者数字]
      bool isalpha() const;    // [至少有一个字符并且所有字符都是字母或者汉字]
      bool isdigit() const;    // [只包含数字]
      bool islower() const;    // [包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是小写]
      bool isspace() const;    // [只包含空白]
      bool istitle() const;    // [是标题化的]
      bool isupper() const;    // [包含至少一个区分大小写的字符,并且所有这些(区分大小写的)字符都是大写]

      // 以指定字符串作为分隔符,将 sequence 中所有的元素(的字符串表示)合并为一个新的字符串
      template <class T>
      str join(T const& sequence) const;

      // 返回一个原字符串左对齐,并使用空格填充至长度 width 的新字符串。
      template <class T>
      str ljust(T const& width) const;
      
      // 转换字符串中所有大写字符为小写.
      str lower() const;
      
      // 截掉字符串左边的空格或指定字符。
      str lstrip() const;

      // 将字符串中的 old 替换成 new_,如果 maxsplit 指定,则替换不超过 maxsplit 次。
      template <class T1, class T2>
      str replace(T1 const& old, T2 const& new_) const;
      template <class T1, class T2, class T3>
      str replace(T1 const& old, T2 const& new_, T3 const& maxsplit) const;

      // 类似于 find(),不过是从右边开始.
      template <class T>
      long rfind(T const& sub) const;
      template <class T1, class T2>
      long rfind(T1 const& sub, T2 const& start) const;
      template <class T1, class T2, class T3>
      long rfind(T1 const& sub, T2 const& start, T3 const& end) const;

      // 类似于 index(),不过是从右边开始.
      template <class T>
      long rindex(T const& sub) const;
      template <class T1, class T2>
      long rindex(T1 const& sub, T2 const& start) const;
      template <class T1, class T2, class T3>
      long rindex(T1 const& sub, T2 const& start, T3 const& end) const;

      // 返回一个原字符串右对齐,并使用默认空格填充至长度 width 的新字符串
      template <class T>
      str rjust(T const& width) const;
    
      // 删除字符串末尾的空格或指定字符。
      str rstrip() const;

      // 以 sep 或者空格为分隔符截取字符串,如果 maxsplit 有指定值,则仅截取 maxsplit+1 个子字符串
      list split() const;
      template <class T>
      list split(T const& sep) const;
      template <class T1, class T2>
      list split(T1 const& sep, T2 const& maxsplit) const;

      // 按照行('\r', '\r\n', \n')分隔,返回一个包含各行作为元素的列表,如果参数 keepends 为 False,不包含换行符,如果为 True,则保留换行符。
      list splitlines() const;
      template <class T>
      list splitlines(T const& keepends) const;

      // 检查字符串是否是以指定子字符串 prefix 开头,是则返回 True,否则返回 False。如果start 和 end 指定值,则在指定范围内检查。
      template <class T>
      bool startswith(T const& prefix) const;
      template <class T1, class T2>
      bool startswidth(T1 const& prefix, T2 const& start) const;
      template <class T1, class T2, class T3>
      bool startswidth(T1 const& prefix, T2 const& start, T3 const& end) const;

      str strip() const;      // 在字符串上执行 lstrip()和 rstrip()
      str swapcase() const;   // 将字符串中大写转换为小写,小写转换为大写
      str title() const;      // 返回"标题化"的字符串,就是说所有单词都是以大写开始,其余字母均为小写

      // 根据 table 给出的表(包含 256 个字符)转换 string 的字符, 要过滤掉的字符放到 deletechars 参数中
      template <class T>
      str translate(T const& table) const;
      template <class T1, class T2>
      str translate(T1 const& table, T2 const& deletechars) const;

      str upper() const;  // 转换字符串中的小写字母为大写
  };
}}

从上面的定义中可以看出,Boost.Python str 类给出的函数与 Python 的原生方法是一一对应的,但是也要注意仍然没有 Python 原生方法灵活,比如有些函数缺乏部分参数,而且 zfill() isdecimal() 等方法并没有包含进来。

示例
C++:

bp::str set_str_as_title (bp::str x)
{
    return x.title();
}

Python:

$ python
>>> import objects
>>> s = "boost wrap str class"
>>> objects.set_str_as_title(s)
'Boost Wrap Str Class'


long class

对于数字,C++ 和 Python 基本上是可以通用的,而且 Python 的这一数据类型也没有什么额外的方法,从 long 的定义也没有看到有什么成员函数。<boost/python/long.hpp>

namespace boost { namespace python
{
  class long_ : public object
  {
   public:
      long_(); // new long_

      template <class T>
      explicit long_(T const& rhs);

      template <class T, class U>
      long_(T const& rhs, U const& base);
  };
}}

示例
对于 long class 类型和直接使用 int 在功能上有什么区别,到目前为止我还不是很了解。
看下面的示例:

namespace bp = boost::python;
int multile_int (int x)
{
    return x * 2;
}

bp::long_ multile_long (bp::long_ x)
{
    int y = bp::extract<int>(x);
    bp::long_ z(y*2);
    
    return z;
}

def("multile_int", multile_int, args("x"), return_value_policy<return_by_value>());
def("multile_long", multile_long, args("x"), return_value_policy<return_by_value>());

对于同样的 Python 参数,其返回值是一样的:

>>> import objects
>>> objects.multile_int(2)
4
>>> objects.multile_long(2)
4

但是需要注意的是在上例中 multile_int() 里的 x 以及返回值都是一个数值,在 C++ 程序里可以直接打印出来。而在 multile_long() 里的 z 是一个类的实例。虽然最后传递到 python 里会拷贝数值,但在 C++ 程序里是不能直接作为数值操作的。

enum class

虽然 Python 没有枚举类型,但是作为 C++ 的基本数据类型,在软件开发的过程中非常常见。在碰到这一类型时,我们经常希望将它作为 int 传递给 Python。 Boost.Python 同样也提供了枚举工具,同时负责从 Python 的动态类型到 C++ 的强静态类型的正确转换(在 C++ 中,int 不能隐式转换为枚举)。

这个类相关定义在 <boost/python/enum.hpp> 中。该头文件定义了用户向 Python 公开其 C++ 枚举类型的接口。其类定义如下:

namespace boost { namespace python
{
  template <class T>
  class enum_ : public object
  {
    enum_(char const* name, char const* doc = 0);    // 构造函数
    enum_<T>& value(char const* name, T x); // 将 x 值与 name 绑定,即设置 name 值为 x。返回类实例本身,即 *this
    enum_<T>& export_values();  // 将当前已定义的枚举值和名称公开,之后属性名称便可在 Python 中直接使用。
  };
}}

创建一个派生自 Python 的 int 类型的 Python 类,该类型与作为其第一个参数传递的 C++ 类型相关联。

enum 的使用与其他派生类不同,为了说明,给定一个 C++ 枚举:

enum choice { red, blue };

需要指定构造函数并将名称和值绑定:

enum_<choice>("choice")
    .value("red", red)
    .value("blue", blue)
    ;

之后 choice 及其元素便可以暴露给 Python。我们可以在 Python 中访问这些值:

>>> my_module.choice.red
my_module.choice.red

其中 my_module 是声明枚举的模块。您还可以围绕一个类创建一个新范围:

scope in_X = class_<X>("X")
                .def( ... )
                .def( ... )
            ;

// Expose X::nested as X.nested
enum_<X::nested>("nested")
    .value("red", red)
    .value("blue", blue)
    ;

新的枚举类型是在当前的 scope() 中创建的,它通常是当前的模块。上面的代码片段创建了一个派生自 Python 的 int 类型的 Python 类,该类型与作为其第一个参数传递的 C++ 类型相关联。

注:scope是一个具有关联的全局 Python 对象的类,该对象控制 Python 命名空间,其中新的扩展类和包装的函数将被定义为属性。其具体说明后面更。

示例
C++:

#include <boost/python/enum.hpp>
#include <boost/python/def.hpp>
#include <boost/python/module.hpp>

using namespace boost::python;

enum color { red = 1, green = 2, blue = 4 };

color identity_(color x) { return x; }

BOOST_PYTHON_MODULE(enums)
{
  enum_<color>("color")
    .value("red", red)
    .value("green", green)
    .export_values()
    .value("blue", blue)
    ;

  def("identity", identity_);
}

Python:

>>> from enums import *

>>> identity(red)
enums.color.red

>>> identity(color.red)
enums.color.red

>>> identity(green)
enums.color.green

>>> identity(color.green)
enums.color.green

>>> identity(blue)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
NameError: name 'blue' is not defined

>>> identity(color.blue)
enums.color.blue

>>> identity(color(1))
enums.color.red

>>> identity(color(2))
enums.color.green

>>> identity(color(3))
enums.color(3)

>>> identity(color(4))
enums.color.blue

>>> identity(1)
Traceback (most recent call last):
  File "<stdin>", line 1, in ?
TypeError: bad argument type for built-in operation

注意上面 Line15 和 Line3/9 的区别,在 Python 程序中可以直接使用 “red”, “green” 作为参数,而 “blue” 不行。这是因为在前面的构造函数中, export_values() 前面的 scope 只包含 “red” “green” 两个值。


参考资料

ObjectWrapper
Object Interface
Chapter 3. Object Wrappers
boost.python object
boost.python list

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

翔底

您的鼓励将是我创作最大的动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值