跳轉到內容

Python 程式設計/使用 C++ 擴充套件

來自華夏公益教科書,開放的書籍,開放的世界


有不同的方法可以使用 C 和 C++ 程式碼擴充套件 Python

  • 使用純 C,使用 Python.h
  • 使用 Swig
  • 使用 Boost.Python,可選擇使用 Py++ 預處理
  • 使用 pybind11
  • 使用 Cython.

本頁描述 Boost.Python。在 Cython 出現之前,它是編寫 C++ 擴充套件模組最舒適的方式。

Boost.Python 與 Boost C++ 庫捆綁在一起。要在 Ubuntu 系統上安裝它,您可能需要執行以下命令

$ sudo apt-get install libboost-python-dev 
$ sudo apt-get install python-dev

一個 Hello World 示例

[編輯 | 編輯原始碼]

C++ 原始碼 (hellomodule.cpp)

[編輯 | 編輯原始碼]
#include <iostream>

using namespace std;

void say_hello(const char* name) {
    cout << "Hello " <<  name << "!\n";
}

#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
using namespace boost::python;

BOOST_PYTHON_MODULE(hello)
{
    def("say_hello", say_hello);
}
#!/usr/bin/env python

from distutils.core import setup
from distutils.extension import Extension

setup(name="PackageName",
    ext_modules=[
        Extension("hello", ["hellomodule.cpp"],
        libraries = ["boost_python"])
    ])

現在我們可以使用以下命令構建我們的模組

python setup.py build

模組 `hello.so` 將最終位於例如 `build/lib.linux-i686-2.4` 中。

使用擴充套件模組

[編輯 | 編輯原始碼]

更改到包含檔案 `hello.so` 的子目錄。在互動式 Python 會話中,您可以按如下方式使用該模組。

>>> import hello
>>> hello.say_hello("World")
Hello World!

一個使用 CGAL 的示例

[編輯 | 編輯原始碼]

CGAL 庫的一些(但不是全部)函式已經有了 Python 繫結。這裡提供了一個沒有這種繫結的案例以及如何實現它的示例。該示例取自 CGAL 文件.

// test.cpp
using namespace std;

/* PYTHON */
#include <boost/python.hpp>
#include <boost/python/module.hpp>
#include <boost/python/def.hpp>
namespace python = boost::python;

/* CGAL */
#include <CGAL/Cartesian.h>
#include <CGAL/Range_segment_tree_traits.h>
#include <CGAL/Range_tree_k.h>

typedef CGAL::Cartesian<double> K;
typedef CGAL::Range_tree_map_traits_2<K, char> Traits;
typedef CGAL::Range_tree_2<Traits> Range_tree_2_type;

typedef Traits::Key Key;
typedef Traits::Interval Interval;

Range_tree_2_type *Range_tree_2 = new Range_tree_2_type;

void create_tree()   {

  typedef Traits::Key Key;                
  typedef Traits::Interval Interval;    

  std::vector<Key> InputList, OutputList;
  InputList.push_back(Key(K::Point_2(8,5.1), 'a'));
  InputList.push_back(Key(K::Point_2(1.0,1.1), 'b'));
  InputList.push_back(Key(K::Point_2(3,2.1), 'c'));

  Range_tree_2->make_tree(InputList.begin(),InputList.end());
  Interval win(Interval(K::Point_2(1,2.1),K::Point_2(8.1,8.2)));
  std::cout << "\n Window Query:\n";
  Range_tree_2->window_query(win, std::back_inserter(OutputList));
  std::vector<Key>::iterator current=OutputList.begin();
  while(current!=OutputList.end()){
      std::cout << "  " << (*current).first.x() << "," << (*current).first.y()
           << ":" << (*current).second << std::endl;
      current++;
    }
  std::cout << "\n Done\n";
}

void initcreate_tree() {;}

using namespace boost::python;
BOOST_PYTHON_MODULE(test)
{
    def("create_tree", create_tree, "");
}
// setup.py
#!/usr/bin/env python
 
from distutils.core import setup
from distutils.extension import Extension
 
setup(name="PackageName",
    ext_modules=[
        Extension("test", ["test.cpp"],
        libraries = ["boost_python"])
    ])

然後我們編譯並執行該模組,如下所示

$ python setup.py build
$ cd build/lib*
$ python
>>> import test
>>> test.create_tree()
Window Query:
 3,2.1:c
 8,5.1:a
Done
>>>

處理 Python 物件和錯誤

[編輯 | 編輯原始碼]

還可以處理更復雜的資料,例如 Python 物件,如列表。使用對物件“attr”函式輸出執行的提取函式訪問屬性。我們也可以透過告訴庫發生了錯誤並返回來丟擲錯誤。在以下情況下,我們編寫了一個名為“afunction”的 C++ 函式,我們希望呼叫它。該函式以整數 N 和長度為 N 的向量作為輸入,我們必須在呼叫該函式之前將 Python 列表轉換為字串向量。

#include <vector>
using namespace std;

void _afunction_wrapper(int N, boost::python::list mapping) {

    int mapping_length = boost::python::extract<int>(mapping.attr("__len__")());
    //Do Error checking, the mapping needs to be at least as long as N 
    if (mapping_length < N) {
        PyErr_SetString(PyExc_ValueError,
            "The string mapping must be at least of length N");
        boost::python::throw_error_already_set();
        return;
    }

    vector<string> mystrings(mapping_length);
    for (int i=0; i<mapping_length; i++) {
        mystrings[i] = boost::python::extract<char const *>(mapping[i]);
    }

   //now call our C++ function
   _afunction(N, mystrings);

}

using namespace boost::python;
BOOST_PYTHON_MODULE(c_afunction)
{
    def("afunction", _afunction_wrapper);
}


[編輯 | 編輯原始碼]
華夏公益教科書