# 简介

# 混合开发

  • 为什么需要混合开发?常见的几种需求如下:

    • 虽然 Python 语言很流行,但某些场景必须使用其它编程语言(比如 Web 网页排版必须使用 HTML 语言)。此时需要混合使用两种编程语言,开发一个程序。
    • 有的软件是用 C/C++ 语言开发的,但程序员想在 Python 脚本中调用这些软件的 API 。
      • 直接的方法是,将这些软件用 Python 语言重写一遍,但工作量太大。
      • 简便的方法是,将这些软件封装为 Python 模块,然后在 Python 代码中调用。
    • Python 属于解释型语言,很多人嫌弃 Python 代码的性能低于 C/C++ 代码,比如运行耗时更久、占用内存更多。
      • 因此,对于 Python 程序中的一些关键环节(比如某个数据结构、某个算法),程序员可以用 C/C++ 代码实现,从而提高性能。
      • 不过,大部分客户对程序的性能要求不高,不必花这么多精力来提升性能。也就金融行业,提高 1% 的性能,就可能增加几百万的利润。
      • 如果想提升 Python 程序的性能,建议先通过火焰图等方式,找到实际上耗时最多、占用内存最多的那部分代码是什么,再针对性优化。比如网络 IO 可能耗时几十秒,用 C/C++ 代码也不能提升性能。
  • 开发一个程序时,一般只使用一种编程语言,如果想混合使用其它语言,怎么办?

    • 可以用其它语言编写另一个程序,编译成可执行文件,供当前程序调用。
    • 可以用其它语言编写另一个程序,运行成为一个独立进程,与当前程序进行网络通信(比如 HTTP 通信),从而协同工作。
    • 可以用其它语言编写一段代码(比如一个函数、一个类),被当前程序调用。本文介绍这种情况。
  • CPython 是基于 C 语言实现的一款 Python 解释器,因此它支持 Python 与 C/C++ 的混合开发。

    • 从 Python 调用 C/C++ 代码,有两种方式:
      • 将 C/C++ 代码编译成 C/C++ 的动态链接库,然后在 Python 代码中调用。
      • 将 C/C++ 代码封装成 Python 的扩展模块,然后在 Python 代码中调用。
    • 从 C/C++ 调用 Python 代码,有两种方式:
      • 将 Python 代码转换成 C/C++ 的动态链接库,然后在 C/C++ 代码中调用。
      • 将 Python 代码转换成 C/C++ 的源文件,然后在 C/C++ 代码中调用。

# 混合开发工具

混合开发工具有多种,选择它们时需要从多方面考虑,比如:

  • 能否从 Python 调用 C/C++ ?或者反之?
  • 能否从 Python 传递一个变量到 C/C++ ?或者反之?
    • 该变量允许采用哪些基本数据类型?
    • 能否自动将 Python 的数据类型,转换成 C/C++ 的数据类型?或者反之?
  • 能否调用函数?
  • 能否调用类?

# CPython API

  • 优点:
    • 它是 CPython 解释器自带的功能,不需要安装第三方库。
    • 它是实现 Python 混合开发的底层 API ,是其它混合开发工具的基础。
    • 它可以将 C/C++ 代码封装成 Python 模块,或者将 Python 代码封装成 C 代码。
  • 缺点:
    • 只提供了底层 API ,直接使用的话很麻烦。

# ctypes

  • 优点:
    • 它是 Python 自带的标准库,不需要安装第三方库。
    • 支持从 Python 加载 C 的动态链接库,直接调用其中的函数。或者将 Python 函数作为回调函数传给 C 函数。
    • 使用时不需要封装 C 代码,可以直接调用 C 的动态链接库。
  • 缺点:
    • 没有封装 C 函数,因此 Python 调用一个 C 函数时需要自己转换数据类型。
    • 只支持 C 语言,因此调用 C++ 代码时,需要先封装成 C 函数。
    • 不支持从 C/C++ 主动调用 Python 代码。

# Cython

  • :Python 的第三方库,可以将 C 代码封装成 Python 模块,或者将 Python 代码编译成 C 代码。
  • 注意区分:CPython 是一个 Python 解释器,Cython 是一个 Python 库。
  • 优点:
    • 可以在 Python 中调用 C/C++ 的数据类型、函数,实现比纯 Python 代码更高的运行效率。

# SWIG

  • :一个编译器,可以将 C/C++ 代码封装成供 C#、Java、Python 等多种语言调用的文件。
  • 缺点:
    • 不支持从 C/C++ 主动调用 Python 。

# Boost.Python

  • :一个 C++ 库,可以将 C++ 代码封装成 Python 模块,或者在 C++ 中导入 Python 模块。
  • Boost 库的使用很广,提供了一些扩展功能的 C++ 库,近乎 C++ 的标准库。

# pybind11

  • :一个 C++ 库,相当于轻量级的 Boost.Python 。
  • 优点:
    • 比较简单,使用时只需要导入一个头文件。但功能完备。
    • 对 C/C++ 代码的封装比较完善,能加上模块说明、函数说明。