{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "(development-python-cython)=\n", "# Cython による C / C++ モジュールの作成\n", "\n", "[Cython](https://cython.org/)\n", "は Python 風の記述で C / C++ によるモジュールを作るライブラリ。\n", "\n", "静的に型を指定することができるため、\n", "Python では遅くなりやすい演算を C 言語の速度で行うことが可能となる。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## インストール\n", "\n", "pip コマンドなどで `cython` パッケージをインストールする。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Jupyter における使用方法\n", "\n", "このページは Jupyter で作成しているため、ここでは Jupyter で Cython を使用する方法を説明する。\n", "\n", "まず、以下の記述により Cython を有効化する。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%load_ext Cython" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "続いて、`%%cython` から始めるセルで対象となる処理を実装する。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%cython\n", "\n", "# 演算が重くなりやすい例として、良くないアルゴリズムでフィボナッチ数列を計算してみる。\n", "\n", "cpdef int fibonacci(int number): # 静的な型はアノテーションでなく C 言語風に前に書く。\n", " if number < 2:\n", " return 1\n", " return fibonacci(number - 1) + fibonacci(number - 2)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "```{hint}\n", "`%%cython` のセルの中は Cython 独特の記述方法が混じった Python 風の言語で記載する。\n", "```" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "`%%cython` の記述をした関数は同じ Jupyter のファイルからは通常の Python と同様に呼び出せる。" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fibonacci(10)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fibonacci(20)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "fibonacci(30)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## 記述例\n", "\n", "以下では色々な関数を記述してみる。\n", "詳しい書き方は [Cython のドキュメント](https://cython.readthedocs.io/) を参照。" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### C 言語の関数の呼び出し" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%cython\n", "\n", "# 試しに C 言語標準ライブラリの中の strlen 関数をあえて Python から呼んでみる。\n", "\n", "# 呼び出す対象の関数の宣言を書く。\n", "cdef extern from \"string.h\":\n", " size_t strlen(const char* string)\n", "\n", "# C 言語の関数をラップして Python から呼べるようにする。\n", "def c_strlen(str string):\n", " \"\"\"C 言語の strlen 関数で文字数を取得する関数。\"\"\"\n", " return strlen(string.encode(\"utf-8\"))" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "c_strlen(\"abc\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "c_strlen(\"テスト\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### C++ の機能の利用" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%cython\n", "\n", "# distutils: language = c++\n", "# 上記の行がないと C++ の機能が使用できない。\n", "\n", "# C++ 標準ライブラリの std::string を読み込む。\n", "from libcpp.string cimport string\n", "\n", "def cpp_str_len(str s):\n", " \"\"\"C++ の std::string::size 関数で文字数を取得する関数。\"\"\"\n", " cdef string cpp_str = s.encode(\"utf-8\")\n", " return cpp_str.size()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cpp_str_len(\"abc\")" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "cpp_str_len(\"テスト\")" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "### 配列の利用" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%%cython\n", "\n", "def sum_in_cython(double[:] values):\n", " \"\"\"Cython でリストの総和を求める。\"\"\"\n", " cdef double sum = 0\n", " for value in values:\n", " sum += value\n", " return sum" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "import numpy\n", "\n", "sum_in_cython(numpy.array([1, 2, 3], dtype=numpy.float64))" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "````{important}\n", "通常の `list` 型のデータを使用すると\n", "```\n", "TypeError: a bytes-like object is required, not 'list'\n", "```\n", "のようなエラーになって実行に失敗する。\n", "````" ] } ], "metadata": { "kernelspec": { "display_name": ".venv", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.8" } }, "nbformat": 4, "nbformat_minor": 2 }