SlideShare una empresa de Scribd logo
1 de 39
Descargar para leer sin conexión
Wrapping a C++ library with Cython



            Tokyo.SciPy #5
              2013-01-26




                                     1 / 39
概要




  Cython を用いた C/C++ライブラリの Python ラッパー作成
  Python/C API
の初歩について説明する.




                                      2 / 39
Outline


1.   Introduction


2.   Cython


3.   Python/C API


4.   Summary




                    3 / 39
1. Introduction




                  4 / 39
動機
     Python と C/C++の両方の長所を活かしたい

 C/C++ 実行速度の速さ
        データ構造, 数値計算ライブラリが揃っている
                   → 計算量が支配的な箇所に使う
 Python 読み書きしやすさ, 柔軟性, 拡張性, ポータビリティ
        利便性の高いライブラリが揃っている
                   → その他のすべての箇所に使う
        データ収集, 前処理
        コマンドライン, GUI アプリ, ウェブアプリ
        設定ファイル, ジョブ管理, ログ管理
        テスト, 可視化, ドキュメンテーション, · · ·

 ⇒ Python から C/C++を呼び出せればよい
                                      5 / 39
6 / 39
Python/C API


Python/C API を用いて Python の拡張モジュールを作成することに
より以下が可能となる.
   新しいオブジェクトの追加
   C/C++の呼び出し



http://docs.python.jp/2/c-api/index.html
http://docs.python.jp/2/extending/extending.html




                                                   7 / 39
say.c

#include <Python.h>
static PyObject* say_hello(PyObject* self, PyObject* args) {
    const char* name;
     if (!PyArg_ParseTuple(args, "s", &name))
        return NULL;

        printf("Hello %s!n", name);
        Py_RETURN_NONE;
}
...

setup.py

setup(name="say", ext_modules=[
   Extension("say", ["say.c"])
])

                                                       8 / 39
$ python setup.py build_ext --inplace
$ python
>>> import say



  Python の内部構造についての知識が必要
  メモリ管理, 例外処理などが面倒
  コード量が多い

 ⇒ 拡張モジュールを作成するためのツールを使う




                                        9 / 39
拡張モジュールを作成するためのツール

C/C++による拡張モジュールを作成するためのツールとして
  Pyrex
  Cython
  SWIG
  SIP
  Boost.Python
などがある.

以下では Cython を用いて C/C++ライブラリの Python ラッパーを
作成する方法について説明する.



                                      10 / 39
2. Cython




            11 / 39
Cython



   Python の拡張モジュールを作成するための言語
   Python + 型宣言を基本とした言語仕様
   CPython 2.4-3.x, Windows/Mac/Linux
   Apache License
   lxml, Numpy, Scipy, Sage, mpi4py, petsc4py, · · ·
   http://cython.org/




                                                       12 / 39
拡張モジュールの作成方法
 1. pyx ファイルを作成する
 2. Cython を用いて pyx ファイルを c/cpp ファイルに変換する
 3. c/cpp ファイルをコンパイルする
生成された so ファイルは Python から直接インポートできる.




setup(ext_modules=cythonize("foo.pyx"))
$ python setup.py build_ext --inplace
$ python
>>> import foo
                                          13 / 39
Cython では Python のソースコードが (ほぼ) そのまま使える

さらに以下のような言語仕様が加えられている.
  型宣言
  C/C++の読み込み
  条件付きコンパイル
  コンパイラディレクティブ
  etc.




                                     14 / 39
型宣言


cdef int i, j[10]
cdef float f, *g
cdef struct Rectangle:
    float width
    float height
cdef enum State:
    open = 1
    closed = 2
cdef object pyobj
ctypedef unsigned long uint64_t
from libc.stdint cimport int64_t




                                   15 / 39
型変換
基本的な数値型と文字列型については, Python オブジェクトと C
変数が自動変換される.

cdef bytes py_byte_string
cdef unicode py_unicode_string
cdef char* c_string

py_byte_string = <bytes> c_string
py_byte_string = c_string
py_byte_string = c_string[:length]
c_string = py_byte_string

py_unicode_string = py_byte_string.decode("utf-8")
py_byte_string = py_unicde_string.encode("utf-8")



                                                     16 / 39
関数定義
def により定義
    引数, 返り値ともに Python オブジェクト
    Python から呼び出せる
cdef により定義
    引数, 返り値ともに C 変数 (Python オブジェクトも含む)
    Python から呼び出せない
def integrate(double a, double b, int N):
    # 引数, 返り値は自動的に型変換される
    cdef int i
    cdef double s, dx
    s = 0; dx = (b - a) / N
    for i in range(N):
        s += f(a + i * dx)
    return s * dx
cdef float f(double x) except *:
    return 1 / x
                                            17 / 39
拡張型
cdef class Interval:
    cdef public float x0, x1
    def __init__(self, x0, x1):
        self.x0 = x0; self.x1 = x1
    @property
    def length(self):
        return self.x1 - self.x0
def widen(Interval i not None, r):
    i.x0 *= r; i.x1 *= r


    ビルトイン型, 拡張型を継承できる. 多重継承はできない.
    アトリビュートには public, readonly を指定できる
    拡張型の値は None を取りうる
    拡張型の引数には not None を指定できる
    <MyClass?> は型チェック付きキャスト
                                     18 / 39
拡張型の初期化

 cinit   C レベルの初期化を行う.
         必ず一度だけ呼び出される.
         この時点では Python オブジェクトとして不完全.
  init   cinit 以外の初期化を行う.
        複数回呼ばれる/1 回も呼ばれない場合もある.
dealloc C レベルの破棄処理.
        この時点では Python オブジェクトとして不完全.
基底型の cinit が先に呼び出される.
コンストラクタに渡した引数は cinit ,    init の両方に渡さ
れる.



                                   19 / 39
C 言語とのシンタックスの違い



 const は使えない
 ヌルポインタは NULL により表す
 p->a の代わりに p.a を使う
 &x の代わりに cython.address(x) を使う
 *p の代わりに p[0] or cython.operator.dereference(p)
 を使う




                                             20 / 39
C の読み込み


Cython は C のヘッダファイルを読まないため, 以下のような宣言
が必要となる.

cdef extern from "math.h":
    double sin(double)
    double M_PI

def py_sin(d):
    # Python から呼び出し可能
    return sin(M_PI / 180.0 * d)




                                   21 / 39
C++の読み込み


  名前空間
  クラス
  テンプレート
  演算子オーバーロード
  ポリモーフィズム
などに対応している.

C++の例外は対応する Python の例外に翻訳される.




                                22 / 39
STL コンテナ


    STL コンテナは libcpp 以下から cimport するだけで使える
    対応する Python 組み込み型があれば自動変換される

from libcpp.string cimport string
cdef string cpp_string
cdef bytes py_byte_string

cpp_string = <string> py_byte_string
cpp_string = py_byte_string
py_byte_string = cpp_string




                                       23 / 39
C++クラスの宣言
pair.pyx

cdef extern from "<utility>" namespace "std":
    cdef cppclass pair[T, U]:
        T first
        U second
        pair() nogil except +
        pair(pair&) nogil except +
        pair(T&, U&) nogil except +
        bint operator==(pair&, pair&) nogil
        bint operator!=(pair&, pair&) nogil
        ...
cdef pair[int, char*] *p = new pair[int, char*](1, "One")

setup.py

setup(ext_modules=cythonize("pair.pyx", language="c++"))

                                                      24 / 39
Python ラッパークラス
cppclass を Python から呼び出すにはラッパークラスが必要.
cdef class PyPair:
    cdef pair[int, char*] *thisptr
    def __cinit__(self, *args, **kw):
        self.thisptr = new pair[int, char*]()
    def __init__(self, int i, char* s):
        self.thisptr.first = i
        self.thisptr.second = s
    def __dealloc__(self):
        del self.thisptr
    @property
    def first(self):
        return self.thisptr.first
    @property
    def second(self):
        return self.thisptr.second
                                                25 / 39
デバッガ


 $ python-dbg setup.py build_ext --pyrex-gdb --inplace
 $ cygdb
 (gdb)

使い方は GDB とほぼ同じ.
   ブレークポイントの設定
   スタックのインスペクション
   ステップ実行
   etc.




                                                     26 / 39
typedness のアノテーション
Cython および C/C++コードを typedness により色分けした HTML
ファイルを生成する.

 $ cython foo.pyx -a




        http://docs.cython.org/src/quickstart/cythonize.html


                                                               27 / 39
プロファイリング


次のディレクティブによりプロファイリングが有効になる.

 # cython: profile=True

使用方法は cProfile を使った Python のプロファイリングと同じ.

cProfile.runctx("extmod.func()",
                globals(), locals(), "Profile.prof")
s = pstats.Stats("Profile.prof")




                                                       28 / 39
その他の機能
 Numpy との連携
 Sage Notebook との連携
 コンパイラディレクティブ
 条件付きコンパイル
 融合型
 型つきメモリビュー
 並列化
 GIL 制御
 etc.


                  詳しくは http://docs.cython.org/


                                         29 / 39
3. Python/C API




                  30 / 39
Cython により生成された C/C++ファイルを読むには Python/C API
の知識が必要となる. 以下ではその初歩について説明する.


 詳しくは http://docs.python.jp/2/extending/index.html




                                             31 / 39
すべてのデータはオブジェクト
#define PyObject_HEAD
    _PyObject_HEAD_EXTRA /* デバグ用*/ 
    Py_ssize_t ob_refcnt; /* 参照カウンタ */ 
    struct _typeobject *ob_type; /* 型オブジェクト */

typedef struct _object {
    PyObject_HEAD
} PyObject;

typedef struct {
    PyObject_HEAD
    long ob_ival;
} PyIntObject;

    PyInt FromLong などで Python オブジェクトを構築
    PyInt Check などで型チェ   ック
    PyInt AsLong などで C 変数を取得
                                                 32 / 39
33 / 39
Python から呼び出す関数の引数, 返り値は Python オブジェクト

static PyObject *
func(PyObject *self, PyObject *args) {
    const char *s;
    if (!PyArg_ParseTuple(args, "s", &s))
        return NULL;
    ...
}
typedef PyObject *(*PyCFunction)(PyObject *, PyObject *);


                    PyErr *で例外処理
if (PyErr_Occurred()) {
  if (/* StopIteration だったら */) PyErr_Clear();
  else { goto __pyx_error; }
}

                                                      34 / 39
PyObject Call*で Python オブジェクトの呼び出し

PyObject* PyObject_Call(PyObject *callable,
                        PyObject *args, PyObject *kw)


    args, kw のチェック, 再帰の管理などが行われる


           ガベージコレクションは参照カウント法

    参照カウントの振る舞い “参照の所有権” により理解される
    Py INCREF, Py DECREF で参照カウンタを増減
    参照カウンタが 0 になったオブジェクトは破棄される


                                                        35 / 39
4. Summary




             36 / 39
まとめ


 Cython を使って C/C++ライブラリの Python ラッパーを
 “手軽に” 作ることが出来る
 拡張ライブラリの仕組みを把握するには
 Python/C API の知識が必要


                    Cython は
      C/C++と Python の両方の長所を活かすための
            橋渡しとしての役割を果たす




                                        37 / 39
References



[1] http://docs.python.jp
[2] http://docs.cython.org/
[3] Cython ユーザメーリングリスト
[4] D. S. Seljebotn, Fast numerical computations with Cython,
    Proceedings of the 8th Python in Science Conference, 2009.




                                                                 38 / 39
fin.




Revision: 9176288 (2013-01-25)

                                       39 / 39

Más contenido relacionado

La actualidad más candente

不均衡データのクラス分類
不均衡データのクラス分類不均衡データのクラス分類
不均衡データのクラス分類
Shintaro Fukushima
 
形状解析のための楕円フーリエ変換
形状解析のための楕円フーリエ変換形状解析のための楕円フーリエ変換
形状解析のための楕円フーリエ変換
Tsukasa Fukunaga
 
Rあんなときこんなとき(tokyo r#12)
Rあんなときこんなとき(tokyo r#12)Rあんなときこんなとき(tokyo r#12)
Rあんなときこんなとき(tokyo r#12)
Shintaro Fukushima
 

La actualidad más candente (20)

[DLHacks 実装] DeepPose: Human Pose Estimation via Deep Neural Networks
[DLHacks 実装] DeepPose: Human Pose Estimation via Deep Neural Networks[DLHacks 実装] DeepPose: Human Pose Estimation via Deep Neural Networks
[DLHacks 実装] DeepPose: Human Pose Estimation via Deep Neural Networks
 
Visualizing Data Using t-SNE
Visualizing Data Using t-SNEVisualizing Data Using t-SNE
Visualizing Data Using t-SNE
 
いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門いまさら聞けない!CUDA高速化入門
いまさら聞けない!CUDA高速化入門
 
[DL輪読会]Deep Face Recognition: A Survey
[DL輪読会]Deep Face Recognition: A Survey[DL輪読会]Deep Face Recognition: A Survey
[DL輪読会]Deep Face Recognition: A Survey
 
Rの高速化
Rの高速化Rの高速化
Rの高速化
 
3D CNNによる人物行動認識の動向
3D CNNによる人物行動認識の動向3D CNNによる人物行動認識の動向
3D CNNによる人物行動認識の動向
 
TVMの次期グラフIR Relayの紹介
TVMの次期グラフIR Relayの紹介TVMの次期グラフIR Relayの紹介
TVMの次期グラフIR Relayの紹介
 
NumPyが物足りない人へのCython入門
NumPyが物足りない人へのCython入門NumPyが物足りない人へのCython入門
NumPyが物足りない人へのCython入門
 
数学カフェ 確率・統計・機械学習回 「速習 確率・統計」
数学カフェ 確率・統計・機械学習回 「速習 確率・統計」数学カフェ 確率・統計・機械学習回 「速習 確率・統計」
数学カフェ 確率・統計・機械学習回 「速習 確率・統計」
 
不均衡データのクラス分類
不均衡データのクラス分類不均衡データのクラス分類
不均衡データのクラス分類
 
さるでも分かりたい9dofで作るクォータニオン姿勢
さるでも分かりたい9dofで作るクォータニオン姿勢さるでも分かりたい9dofで作るクォータニオン姿勢
さるでも分かりたい9dofで作るクォータニオン姿勢
 
数式をnumpyに落としこむコツ
数式をnumpyに落としこむコツ数式をnumpyに落としこむコツ
数式をnumpyに落としこむコツ
 
論文紹介「PointNetLK: Robust & Efficient Point Cloud Registration Using PointNet」
論文紹介「PointNetLK: Robust & Efficient Point Cloud Registration Using PointNet」論文紹介「PointNetLK: Robust & Efficient Point Cloud Registration Using PointNet」
論文紹介「PointNetLK: Robust & Efficient Point Cloud Registration Using PointNet」
 
形状解析のための楕円フーリエ変換
形状解析のための楕円フーリエ変換形状解析のための楕円フーリエ変換
形状解析のための楕円フーリエ変換
 
[DL輪読会]Clebsch–Gordan Nets: a Fully Fourier Space Spherical Convolutional Neu...
[DL輪読会]Clebsch–Gordan Nets: a Fully Fourier Space Spherical Convolutional Neu...[DL輪読会]Clebsch–Gordan Nets: a Fully Fourier Space Spherical Convolutional Neu...
[DL輪読会]Clebsch–Gordan Nets: a Fully Fourier Space Spherical Convolutional Neu...
 
Rあんなときこんなとき(tokyo r#12)
Rあんなときこんなとき(tokyo r#12)Rあんなときこんなとき(tokyo r#12)
Rあんなときこんなとき(tokyo r#12)
 
CRF を使った Web 本文抽出
CRF を使った Web 本文抽出CRF を使った Web 本文抽出
CRF を使った Web 本文抽出
 
Feature Selection with R / in JP
Feature Selection with R / in JPFeature Selection with R / in JP
Feature Selection with R / in JP
 
Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2
Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2
Optuna Dashboardの紹介と設計解説 - 2022/12/10 Optuna Meetup #2
 
[DL輪読会]Deep High-Resolution Representation Learning for Human Pose Estimation
[DL輪読会]Deep High-Resolution Representation Learning for Human Pose Estimation[DL輪読会]Deep High-Resolution Representation Learning for Human Pose Estimation
[DL輪読会]Deep High-Resolution Representation Learning for Human Pose Estimation
 

Destacado

Hpcビジネスコンテンスト発表資料
Hpcビジネスコンテンスト発表資料Hpcビジネスコンテンスト発表資料
Hpcビジネスコンテンスト発表資料
Hironori Nakajo
 
ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発
papamitra
 
Pythonの開発環境を調べてみた
Pythonの開発環境を調べてみたPythonの開発環境を調べてみた
Pythonの開発環境を調べてみた
Kenji NAKAGAKI
 
数理最適化とPython
数理最適化とPython数理最適化とPython
数理最適化とPython
Yosuke Onoue
 
ヒカルのGo 資料 Webアプリケーションの作り方
ヒカルのGo 資料 Webアプリケーションの作り方ヒカルのGo 資料 Webアプリケーションの作り方
ヒカルのGo 資料 Webアプリケーションの作り方
Yosuke Furukawa
 

Destacado (20)

No te comas la coma
No te comas la comaNo te comas la coma
No te comas la coma
 
Scalaと過ごした5ヶ月間
Scalaと過ごした5ヶ月間Scalaと過ごした5ヶ月間
Scalaと過ごした5ヶ月間
 
Hpcビジネスコンテンスト発表資料
Hpcビジネスコンテンスト発表資料Hpcビジネスコンテンスト発表資料
Hpcビジネスコンテンスト発表資料
 
Pythonについて
PythonについてPythonについて
Pythonについて
 
Pythonおじさんのweb2py挑戦記
Pythonおじさんのweb2py挑戦記Pythonおじさんのweb2py挑戦記
Pythonおじさんのweb2py挑戦記
 
ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発ScalaでAndroidアプリ開発
ScalaでAndroidアプリ開発
 
Scala初心者がPlay/ScalaでロックなWebアプリを作ったお話
Scala初心者がPlay/ScalaでロックなWebアプリを作ったお話Scala初心者がPlay/ScalaでロックなWebアプリを作ったお話
Scala初心者がPlay/ScalaでロックなWebアプリを作ったお話
 
Scala 初めての人が Heroku で Web アプリを公開するまで
Scala 初めての人が Heroku で Web アプリを公開するまでScala 初めての人が Heroku で Web アプリを公開するまで
Scala 初めての人が Heroku で Web アプリを公開するまで
 
多分モダンなWebアプリ開発
多分モダンなWebアプリ開発多分モダンなWebアプリ開発
多分モダンなWebアプリ開発
 
Pythonの開発環境を調べてみた
Pythonの開発環境を調べてみたPythonの開発環境を調べてみた
Pythonの開発環境を調べてみた
 
数理最適化とPython
数理最適化とPython数理最適化とPython
数理最適化とPython
 
めんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scalaめんどくさくない Scala #kwkni_scala
めんどくさくない Scala #kwkni_scala
 
コンピュータビジョンの最新ソフトウェア開発環境 SSII2015 チュートリアル hayashi
コンピュータビジョンの最新ソフトウェア開発環境 SSII2015 チュートリアル hayashiコンピュータビジョンの最新ソフトウェア開発環境 SSII2015 チュートリアル hayashi
コンピュータビジョンの最新ソフトウェア開発環境 SSII2015 チュートリアル hayashi
 
ヒカルのGo 資料 Webアプリケーションの作り方
ヒカルのGo 資料 Webアプリケーションの作り方ヒカルのGo 資料 Webアプリケーションの作り方
ヒカルのGo 資料 Webアプリケーションの作り方
 
Pythonによるwebアプリケーション入門 - Django編-
Pythonによるwebアプリケーション入門 - Django編- Pythonによるwebアプリケーション入門 - Django編-
Pythonによるwebアプリケーション入門 - Django編-
 
FINAL FANTASY Record Keeperを支えたGolang
FINAL FANTASY Record Keeperを支えたGolangFINAL FANTASY Record Keeperを支えたGolang
FINAL FANTASY Record Keeperを支えたGolang
 
GoでMinecraftっぽいの作る
GoでMinecraftっぽいの作るGoでMinecraftっぽいの作る
GoでMinecraftっぽいの作る
 
【初心者向け】Go言語勉強会資料
 【初心者向け】Go言語勉強会資料 【初心者向け】Go言語勉強会資料
【初心者向け】Go言語勉強会資料
 
Go MobileでAndroidアプリ開発
Go MobileでAndroidアプリ開発Go MobileでAndroidアプリ開発
Go MobileでAndroidアプリ開発
 
PythonによるWebスクレイピング入門
PythonによるWebスクレイピング入門PythonによるWebスクレイピング入門
PythonによるWebスクレイピング入門
 

Similar a Wrapping a C++ library with Cython

T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
伸男 伊藤
 
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
kiki utagawa
 
Git pyfes201207-presen
Git pyfes201207-presenGit pyfes201207-presen
Git pyfes201207-presen
Kouhei Maeda
 
Boost.python
Boost.pythonBoost.python
Boost.python
fate_fox
 
C++ lecture-0
C++ lecture-0C++ lecture-0
C++ lecture-0
sunaemon
 
C++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みくださいC++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みください
digitalghost
 

Similar a Wrapping a C++ library with Cython (20)

Cython intro prelerease
Cython intro prelereaseCython intro prelerease
Cython intro prelerease
 
サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23
サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23
サイバーエージェントにおけるMLOpsに関する取り組み at PyDataTokyo 23
 
T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門T69 c++cli ネイティブライブラリラッピング入門
T69 c++cli ネイティブライブラリラッピング入門
 
Python physicalcomputing
Python physicalcomputingPython physicalcomputing
Python physicalcomputing
 
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
Pythonの処理系はどのように実装され,どのように動いているのか? 我々はその実態を調査すべくアマゾンへと飛んだ.
 
C#勉強会
C#勉強会C#勉強会
C#勉強会
 
Git pyfes201207-presen
Git pyfes201207-presenGit pyfes201207-presen
Git pyfes201207-presen
 
研究生のためのC++ no.2
研究生のためのC++ no.2研究生のためのC++ no.2
研究生のためのC++ no.2
 
Boost.python
Boost.pythonBoost.python
Boost.python
 
Boost.python
Boost.pythonBoost.python
Boost.python
 
C++ lecture-0
C++ lecture-0C++ lecture-0
C++ lecture-0
 
Python 学習教材 (~299ページ)
Python 学習教材 (~299ページ)Python 学習教材 (~299ページ)
Python 学習教材 (~299ページ)
 
C++0x総復習
C++0x総復習C++0x総復習
C++0x総復習
 
.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#.NET Core 2.x 時代の C#
.NET Core 2.x 時代の C#
 
osakapy 2014.05 LT
osakapy 2014.05 LTosakapy 2014.05 LT
osakapy 2014.05 LT
 
C++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みくださいC++コンパイラ GCCとClangからのメッセージをお読みください
C++コンパイラ GCCとClangからのメッセージをお読みください
 
C++プログラマの為のセキュリティ入門
C++プログラマの為のセキュリティ入門C++プログラマの為のセキュリティ入門
C++プログラマの為のセキュリティ入門
 
C++14 Overview
C++14 OverviewC++14 Overview
C++14 Overview
 
競技プログラミングのためのC++入門
競技プログラミングのためのC++入門競技プログラミングのためのC++入門
競技プログラミングのためのC++入門
 
ひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指すひのきのぼうだけで全クリ目指す
ひのきのぼうだけで全クリ目指す
 

Wrapping a C++ library with Cython

  • 1. Wrapping a C++ library with Cython Tokyo.SciPy #5 2013-01-26 1 / 39
  • 2. 概要 Cython を用いた C/C++ライブラリの Python ラッパー作成 Python/C API の初歩について説明する. 2 / 39
  • 3. Outline 1. Introduction 2. Cython 3. Python/C API 4. Summary 3 / 39
  • 5. 動機 Python と C/C++の両方の長所を活かしたい C/C++ 実行速度の速さ データ構造, 数値計算ライブラリが揃っている → 計算量が支配的な箇所に使う Python 読み書きしやすさ, 柔軟性, 拡張性, ポータビリティ 利便性の高いライブラリが揃っている → その他のすべての箇所に使う データ収集, 前処理 コマンドライン, GUI アプリ, ウェブアプリ 設定ファイル, ジョブ管理, ログ管理 テスト, 可視化, ドキュメンテーション, · · · ⇒ Python から C/C++を呼び出せればよい 5 / 39
  • 7. Python/C API Python/C API を用いて Python の拡張モジュールを作成することに より以下が可能となる. 新しいオブジェクトの追加 C/C++の呼び出し http://docs.python.jp/2/c-api/index.html http://docs.python.jp/2/extending/extending.html 7 / 39
  • 8. say.c #include <Python.h> static PyObject* say_hello(PyObject* self, PyObject* args) { const char* name; if (!PyArg_ParseTuple(args, "s", &name)) return NULL; printf("Hello %s!n", name); Py_RETURN_NONE; } ... setup.py setup(name="say", ext_modules=[ Extension("say", ["say.c"]) ]) 8 / 39
  • 9. $ python setup.py build_ext --inplace $ python >>> import say Python の内部構造についての知識が必要 メモリ管理, 例外処理などが面倒 コード量が多い ⇒ 拡張モジュールを作成するためのツールを使う 9 / 39
  • 10. 拡張モジュールを作成するためのツール C/C++による拡張モジュールを作成するためのツールとして Pyrex Cython SWIG SIP Boost.Python などがある. 以下では Cython を用いて C/C++ライブラリの Python ラッパーを 作成する方法について説明する. 10 / 39
  • 11. 2. Cython 11 / 39
  • 12. Cython Python の拡張モジュールを作成するための言語 Python + 型宣言を基本とした言語仕様 CPython 2.4-3.x, Windows/Mac/Linux Apache License lxml, Numpy, Scipy, Sage, mpi4py, petsc4py, · · · http://cython.org/ 12 / 39
  • 13. 拡張モジュールの作成方法 1. pyx ファイルを作成する 2. Cython を用いて pyx ファイルを c/cpp ファイルに変換する 3. c/cpp ファイルをコンパイルする 生成された so ファイルは Python から直接インポートできる. setup(ext_modules=cythonize("foo.pyx")) $ python setup.py build_ext --inplace $ python >>> import foo 13 / 39
  • 14. Cython では Python のソースコードが (ほぼ) そのまま使える さらに以下のような言語仕様が加えられている. 型宣言 C/C++の読み込み 条件付きコンパイル コンパイラディレクティブ etc. 14 / 39
  • 15. 型宣言 cdef int i, j[10] cdef float f, *g cdef struct Rectangle: float width float height cdef enum State: open = 1 closed = 2 cdef object pyobj ctypedef unsigned long uint64_t from libc.stdint cimport int64_t 15 / 39
  • 16. 型変換 基本的な数値型と文字列型については, Python オブジェクトと C 変数が自動変換される. cdef bytes py_byte_string cdef unicode py_unicode_string cdef char* c_string py_byte_string = <bytes> c_string py_byte_string = c_string py_byte_string = c_string[:length] c_string = py_byte_string py_unicode_string = py_byte_string.decode("utf-8") py_byte_string = py_unicde_string.encode("utf-8") 16 / 39
  • 17. 関数定義 def により定義 引数, 返り値ともに Python オブジェクト Python から呼び出せる cdef により定義 引数, 返り値ともに C 変数 (Python オブジェクトも含む) Python から呼び出せない def integrate(double a, double b, int N): # 引数, 返り値は自動的に型変換される cdef int i cdef double s, dx s = 0; dx = (b - a) / N for i in range(N): s += f(a + i * dx) return s * dx cdef float f(double x) except *: return 1 / x 17 / 39
  • 18. 拡張型 cdef class Interval: cdef public float x0, x1 def __init__(self, x0, x1): self.x0 = x0; self.x1 = x1 @property def length(self): return self.x1 - self.x0 def widen(Interval i not None, r): i.x0 *= r; i.x1 *= r ビルトイン型, 拡張型を継承できる. 多重継承はできない. アトリビュートには public, readonly を指定できる 拡張型の値は None を取りうる 拡張型の引数には not None を指定できる <MyClass?> は型チェック付きキャスト 18 / 39
  • 19. 拡張型の初期化 cinit C レベルの初期化を行う. 必ず一度だけ呼び出される. この時点では Python オブジェクトとして不完全. init cinit 以外の初期化を行う. 複数回呼ばれる/1 回も呼ばれない場合もある. dealloc C レベルの破棄処理. この時点では Python オブジェクトとして不完全. 基底型の cinit が先に呼び出される. コンストラクタに渡した引数は cinit , init の両方に渡さ れる. 19 / 39
  • 20. C 言語とのシンタックスの違い const は使えない ヌルポインタは NULL により表す p->a の代わりに p.a を使う &x の代わりに cython.address(x) を使う *p の代わりに p[0] or cython.operator.dereference(p) を使う 20 / 39
  • 21. C の読み込み Cython は C のヘッダファイルを読まないため, 以下のような宣言 が必要となる. cdef extern from "math.h": double sin(double) double M_PI def py_sin(d): # Python から呼び出し可能 return sin(M_PI / 180.0 * d) 21 / 39
  • 22. C++の読み込み 名前空間 クラス テンプレート 演算子オーバーロード ポリモーフィズム などに対応している. C++の例外は対応する Python の例外に翻訳される. 22 / 39
  • 23. STL コンテナ STL コンテナは libcpp 以下から cimport するだけで使える 対応する Python 組み込み型があれば自動変換される from libcpp.string cimport string cdef string cpp_string cdef bytes py_byte_string cpp_string = <string> py_byte_string cpp_string = py_byte_string py_byte_string = cpp_string 23 / 39
  • 24. C++クラスの宣言 pair.pyx cdef extern from "<utility>" namespace "std": cdef cppclass pair[T, U]: T first U second pair() nogil except + pair(pair&) nogil except + pair(T&, U&) nogil except + bint operator==(pair&, pair&) nogil bint operator!=(pair&, pair&) nogil ... cdef pair[int, char*] *p = new pair[int, char*](1, "One") setup.py setup(ext_modules=cythonize("pair.pyx", language="c++")) 24 / 39
  • 25. Python ラッパークラス cppclass を Python から呼び出すにはラッパークラスが必要. cdef class PyPair: cdef pair[int, char*] *thisptr def __cinit__(self, *args, **kw): self.thisptr = new pair[int, char*]() def __init__(self, int i, char* s): self.thisptr.first = i self.thisptr.second = s def __dealloc__(self): del self.thisptr @property def first(self): return self.thisptr.first @property def second(self): return self.thisptr.second 25 / 39
  • 26. デバッガ $ python-dbg setup.py build_ext --pyrex-gdb --inplace $ cygdb (gdb) 使い方は GDB とほぼ同じ. ブレークポイントの設定 スタックのインスペクション ステップ実行 etc. 26 / 39
  • 27. typedness のアノテーション Cython および C/C++コードを typedness により色分けした HTML ファイルを生成する. $ cython foo.pyx -a http://docs.cython.org/src/quickstart/cythonize.html 27 / 39
  • 28. プロファイリング 次のディレクティブによりプロファイリングが有効になる. # cython: profile=True 使用方法は cProfile を使った Python のプロファイリングと同じ. cProfile.runctx("extmod.func()", globals(), locals(), "Profile.prof") s = pstats.Stats("Profile.prof") 28 / 39
  • 29. その他の機能 Numpy との連携 Sage Notebook との連携 コンパイラディレクティブ 条件付きコンパイル 融合型 型つきメモリビュー 並列化 GIL 制御 etc. 詳しくは http://docs.cython.org/ 29 / 39
  • 30. 3. Python/C API 30 / 39
  • 31. Cython により生成された C/C++ファイルを読むには Python/C API の知識が必要となる. 以下ではその初歩について説明する. 詳しくは http://docs.python.jp/2/extending/index.html 31 / 39
  • 32. すべてのデータはオブジェクト #define PyObject_HEAD _PyObject_HEAD_EXTRA /* デバグ用*/ Py_ssize_t ob_refcnt; /* 参照カウンタ */ struct _typeobject *ob_type; /* 型オブジェクト */ typedef struct _object { PyObject_HEAD } PyObject; typedef struct { PyObject_HEAD long ob_ival; } PyIntObject; PyInt FromLong などで Python オブジェクトを構築 PyInt Check などで型チェ ック PyInt AsLong などで C 変数を取得 32 / 39
  • 34. Python から呼び出す関数の引数, 返り値は Python オブジェクト static PyObject * func(PyObject *self, PyObject *args) { const char *s; if (!PyArg_ParseTuple(args, "s", &s)) return NULL; ... } typedef PyObject *(*PyCFunction)(PyObject *, PyObject *); PyErr *で例外処理 if (PyErr_Occurred()) { if (/* StopIteration だったら */) PyErr_Clear(); else { goto __pyx_error; } } 34 / 39
  • 35. PyObject Call*で Python オブジェクトの呼び出し PyObject* PyObject_Call(PyObject *callable, PyObject *args, PyObject *kw) args, kw のチェック, 再帰の管理などが行われる ガベージコレクションは参照カウント法 参照カウントの振る舞い “参照の所有権” により理解される Py INCREF, Py DECREF で参照カウンタを増減 参照カウンタが 0 になったオブジェクトは破棄される 35 / 39
  • 36. 4. Summary 36 / 39
  • 37. まとめ Cython を使って C/C++ライブラリの Python ラッパーを “手軽に” 作ることが出来る 拡張ライブラリの仕組みを把握するには Python/C API の知識が必要 Cython は C/C++と Python の両方の長所を活かすための 橋渡しとしての役割を果たす 37 / 39
  • 38. References [1] http://docs.python.jp [2] http://docs.cython.org/ [3] Cython ユーザメーリングリスト [4] D. S. Seljebotn, Fast numerical computations with Cython, Proceedings of the 8th Python in Science Conference, 2009. 38 / 39