下面介绍一些有用的技术,您可以在使用Boost.Python包装代码时使用这些技术。

创建包

Python包是一组模块,为用户提供某种功能。 如果您不熟悉如何创建包, Python教程中提供了对它们的一个很好的介绍。

但是我们使用Boost.Python包装C ++代码。 我们如何为用户提供一个漂亮的包界面? 为了更好地解释一些概念,让我们使用一个例子。

我们有一个有不同含义的C ++库:读取和写入各种格式,对声音数据应用滤波器等。它被命名(方便) sounds 。 我们的库已经有了一个简洁的C ++命名空间层次结构,如下所示:

sounds::core
sounds::io
sounds::filters

我们想向Python用户提供相同的层次结构,允许他编写如下代码:

import sounds.filters
sounds.filters.echo(...) # echo is a C++ function

第一步是编写包装代码。 我们必须使用Boost.Python单独导出每个模块,如下所示:

/* file core.cpp */
BOOST_PYTHON_MODULE(core)
{/* export everything in the sounds::core namespace */...
}/* file io.cpp */
BOOST_PYTHON_MODULE(io)
{/* export everything in the sounds::io namespace */...
}/* file filters.cpp */
BOOST_PYTHON_MODULE(filters)
{/* export everything in the sounds::filters namespace */...
}

编译这些文件将生成以下Python扩展: core.pyd , io.pydio.pyd 。

注意

扩展名.pyd用于python扩展模块,它们只是共享库。 使用系统的默认设置,例如Unix的.so和Windows的.dll ,也可以。

现在,我们为Python包创建这个目录结构:

sounds/__init__.pycore.pydfilters.pydio.pyd

文件__init__.py告诉Python该目录sounds/实际上是一个Python包。 它可以是一个空文件,但也可以执行一些魔术,稍后将会显示。

现在我们的包准备好了。 用户所要做的就是将sounds放入他的PYTHONPATH并启动解释器:

>>> import sounds.io
>>> import sounds.filters
>>> sound = sounds.io.open('file.mp3')
>>> new_sound = sounds.filters.echo(sound, 1.0)

很不错吧?

这是创建包层次结构的最简单方法,但它不是很灵活。 如果我们想要将 Python函数添加到过滤器包中,例如,一次在声音对象中应用3个过滤器,该怎么办? 当然,您可以在C ++中执行此操作并将其导出,但为什么不在Python中执行此操作? 您不必重新编译扩展模块,而且编写它会更容易。

如果我们想要这种灵活性,我们将不得不使我们的包层次结构复杂化。 首先,我们将不得不更改扩展模块的名称:

/* file core.cpp */
BOOST_PYTHON_MODULE(_core)
{.../* export everything in the sounds::core namespace */
}

请注意,我们在模块名称中添加了下划线。 文件名也必须更改为_core.pyd ,我们对其他扩展模块执行相同的操作。 现在,我们改变我们的包层次结构如下:

sounds/__init__.pycore/__init__.pycore.pydfilters/\_init__.pyfilters.pydio/\_init__.py_io.pyd

请注意,我们为每个扩展模块创建了一个目录,并为每个扩展模块添加了__init__.py。 但是如果我们这样离开,用户将不得不使用以下语法访问核心模块中的函数:

>>> import sounds.core._core
>>> sounds.core._core.foo(...)

这不是我们想要的。 但是这里输入__init__.py魔术:用户可以直接访问带到__init__.py命名空间的所有内容。 因此,我们所要做的就是将整个命名空间从_core.pyd带到core/__init__.py 。 所以将这行代码添加到sounds/core/__init__.py :

from _core import *

我们对其他包也这样做。 现在,用户像以前一样访问扩展模块中的函数和类:

>>> import sounds.filters
>>> sounds.filters.echo(...)

另外一个好处是我们可以轻松地将纯Python函数添加到任何模块中,这样用户就无法区分C ++函数和Python函数。 让我们将一个 Python函数echo_noise添加到filters包中。 此函数在给定的sound对象中按顺序应用echonoise滤波器。 我们创建一个名为sounds/filters/echo_noise.py的文件并编写我们的函数:

import _filters
def echo_noise(sound):s = _filters.echo(sound)s = _filters.noise(sound)return s

接下来,我们将此行添加到sounds/filters/__init__.py :

from echo_noise import echo_noise

就是这样。 用户现在可以像filters包中的任何其他功能一样访问此功能:

>>> import sounds.filters
>>> sounds.filters.echo_noise(...)

在Python中扩展包装对象

由于Python的灵活性,您可以轻松地向类添加新方法,即使它已经创建了:

>>> class C(object): pass
>>>
>>> # a regular function
>>> def C_str(self): return 'A C instance!'
>>>
>>> # now we turn it in a member function
>>> C.__str__ = C_str
>>>
>>> c = C()
>>> print c
A C instance!
>>> C_str(c)
A C instance!

是的,Python rox。 

我们可以对使用Boost.Python包装的类执行相同的操作。 假设我们在C ++中有一个类point :

class point {...};BOOST_PYTHON_MODULE(_geom)
{class_<point>("point")...;
}

如果我们使用上一个会话创建包中的技术 ,我们可以直接编码到geom/__init__.py :

from _geom import *# a regular function
def point_str(self):return str((self.x, self.y))# now we turn it into a member function
point.__str__ = point_str

从C ++创建的所有点实例也将具有此成员函数! 这种技术有几个优点:

您甚至可以使用元类添加一点语法糖。 让我们创建一个特殊的元类,在其他类中“注入”方法。

# The one Boost.Python uses for all wrapped classes.
# You can use here any class exported by Boost instead of "point"
BoostPythonMetaclass = point.__class__class injector(object):class __metaclass__(BoostPythonMetaclass):def __init__(self, name, bases, dict):for b in bases:if type(b) not in (self, type):for k,v in dict.items():setattr(b,k,v)return type.__init__(self, name, bases, dict)# inject some methods in the point foo
class more_point(injector, point):def __repr__(self):return 'Point(x=%s, y=%s)' % (self.x, self.y)def foo(self):print 'foo!'

现在让我们看看它是如何得到的:

>>> print point()
Point(x=10, y=10)
>>> point().foo()
foo!

另一个有用的想法是用工厂函数替换构造函数:

_point = pointdef point(x=0, y=0):return _point(x, y)

在这个简单的情况下,没有太多的收获,但对于具有许多重载和/或参数的构造函数,这通常是一个很大的简化,同样几乎没有内存占用和关键字支持的零编译时开销。

缩短编译时间

如果您曾经导出过很多类,那么您知道编译Boost.Python包装器需要相当长的时间。 此外,内存消耗很容易变得太高。 如果这导致您出现问题,可以将class_ definitions拆分为多个文件:

/* file point.cpp */
#include <point.h>
#include <boost/python.hpp>void export_point()
{class_<point>("point")...;
}/* file triangle.cpp */
#include <triangle.h>
#include <boost/python.hpp>void export_triangle()
{class_<triangle>("triangle")...;
}

现在,您创建一个main.cpp文件,其中包含BOOST_PYTHON_MODULE宏,并调用其中的各种导出函数。

void export_point();
void export_triangle();BOOST_PYTHON_MODULE(_geom)
{export_point();export_triangle();
}

编译并链接所有这些文件会产生与通常方法相同的结果:

#include <boost/python.hpp>
#include <point.h>
#include <triangle.h>BOOST_PYTHON_MODULE(_geom)
{class_<point>("point")...;class_<triangle>("triangle")...;
}

但记忆得到了控制。

如果您正在开发C ++库并同时将其导出到Python,也建议使用此方法:类中的更改只需要编译单个cpp,而不是整个包装器代码。

注意

如果在编译大型源文件时收到错误消息“致命错误C1204:编译器限制:内部结构溢出” ,此方法也很有用,如FAQ中所述。

Boost.Python教程:通用技术相关推荐

  1. Boost.Python教程:函数

    在本章中,我们将更详细地介绍Boost.Python驱动的函数.我们将看到一些工具,可以将C ++函数暴露给Python,避免潜在的pifall,例如悬空指针和引用. 我们还将看到一些工具,使我们更容 ...

  2. 【通用技术】2个月精通Python爬虫——3大爬虫框架+6场实战+分布式爬虫,包教包会...

    网络爬虫(又被称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动的抓取信息的程序或者脚本. 网络爬虫是互联网上进行信息采集的通用手段,在互联网的各个专业方向上都是不可或缺的底层技术支撑.本课程从爬 ...

  3. python后端教程_Python学习教程(技术干货):关于前后端分离开发入门

    原标题:Python学习教程(技术干货):关于前后端分离开发入门 对于程序员来说,其实Tab和空格远远不只是"立场"问题那么简单. 在不同的编辑器里tab的长度可能不一致,所以在一 ...

  4. python与seo实战课程下载_黑帽seo教程:SEO快排套路与SEO快排Python应用编程技术(零基础)...

    黑帽seo教程:SEO快排套路与SEO快排Python应用编程技术(零基础) 授课内容简介 两个模块:「SEO套路」和「SEO应用编程」 「SEO套路」模块,分 "域名.内容&模板. ...

  5. python文件打包技术免费教程

    需求:如何把python文件转化为像电脑软件一样可执行的程序? 技术:这就需要运用到python文件打包技术了.将python文件打包成exe文件,可以在电脑直接运行,也方便向小伙伴分享你的代码执行成 ...

  6. python教程书籍-大牛推荐的10本学习 Python 的好书

    Python:蛇亚目蟒科,主要包括分布于非洲及亚洲的无毒蟒蛇. Python:Richard Clabaugh拍摄的恐怖电影,2000年发行. Python:澳大利亚汽车公司. Python:英国偶发 ...

  7. Python教程 - Django

    Django 系统 环境 Python 3.6 Django 1.8 参考资料 [Django中文教程](https://yiyibooks.cn/xx/django_182/index.html) ...

  8. python人工智能图像识别_人工智能之Python人脸识别技术,人人都能做识别!

    原标题:人工智能之Python人脸识别技术,人人都能做识别! 作者丨Python小哥哥 https://www.jianshu.com/p/dce1498ef0ee 一.环境搭建 1.系统环境 Ubu ...

  9. 30分钟 Python 教程

    Python 教程 本教程以最简单的方式力求全面介绍常用和常见python语法及相关特性. 本教程适用于有一定的编程(C/C++/Java/C#/js等)基础的人员. 作者-dwSun Python介 ...

最新文章

  1. 【java下午茶系列】java三重奏之封装
  2. 皮一皮:这年头,没看过火影还没法做医生了...
  3. 1. 金融数学中的随机变分法-Wiener空间与Wiener泛函
  4. 数据库视频总结一(概述)
  5. MySQL启动mycat分库分表报错Java HotSpotTM 64-Bit Server VM warning: ignoring option MaxPermSize=64M
  6. 完美国际真数苹果_章子怡玩出新花样,雷人造型别有韵味!和小苹果同框犹如亲姐妹...
  7. 抖音直播APP软件系统为什么能这么火?反映出的问题又会是什么?
  8. M1 Mac:支持 USB-C,但不完全支持
  9. DB First .edmx
  10. SpringBoot java配置类@Configuration 的两种写法
  11. ArcGIS学习总结(11)——创建点要素并计算对应经纬度
  12. Jprofiler激活码
  13. b站python_python学习 —— B站抢楼原理
  14. FAT32、exFAT、NTFS
  15. java 跳跃表_你真的了解跳跃表吗
  16. 【NLP】自然语言处理的语料库与词库
  17. Android笔记:自定义锁屏
  18. 【好用的办公软件】万彩办公大师教程丨标准安装版/绿色免安装版/离线版区别
  19. 苹果刷机服务器验证失败,iPhone手机刷机报错最全总结 教你学会分析手机问题出在哪...
  20. MATLAB中求最大/最小值max/min函数

热门文章

  1. MySQL删除重复行
  2. Linux ls -l ll ln介绍
  3. 微信小程序 模仿拼多多搜索页
  4. 最小代价树(动态规划)
  5. 面试时如何做自我介绍
  6. 如何获取中文文献的英文参考文献信息
  7. 我对研究生生活规划的改变历程
  8. 【R言R语】系列之算法工程师入职半年的总结与感悟
  9. java httpclient cdn_通过FD耗尽实验谈谈使用HttpClient的正确姿势
  10. RNAseq基础(项目设计,方法原理)