Cython(サイソン)は、Pythonに近い文法で書いたコードをC言語のソースへ変換し、CPythonの拡張モジュールとしてコンパイルするツールです。速くなるのは、変数や引数にCの型を宣言して、Pythonオブジェクトを介した演算をCの演算に置き換えた部分です。本記事では、2026年8月22日公開のCython 3.3.0と、10月9日公開のPython 3.15.0を使い、インストールからビルド、def・cdef・cpdefの違い、拡張型(cdef class)、NumPy配列、C++の呼び出し、ビルドエラーの対処までを、手元で動かした結果とあわせて解説します。
まとめ:Cythonで速くなる条件と始め方
- 正体:
.pyx(またはPythonファイル)をCへ変換し、importできる拡張モジュール(.so/.pyd)を作るコンパイラ。読み方は「サイソン」。Python本体の実装であるCPythonとは別物。 - 導入:
pip install cythonまたはconda install -c conda-forge cython。ビルドにはCコンパイラが別途必要(WindowsはMicrosoft C++ Build Tools、macOSはXcode Command Line Tools)。 - 効く条件:変数と引数にCの型を宣言した数値ループ。Python 3.15.0での計測では、型を付けずにコンパイルしただけでは速くならず(2.42秒→2.46秒)、
cdef doubleなどを付けると約120倍になった。 - 効かない条件:NumPyの1命令で書ける処理、I/O待ちが中心の処理。配列の合計はCythonのループ(0.0219秒)よりNumPyの
sum()(0.0088秒)が速かった。 - 最新版:3.3.0(2026-08-22)。Python 3.9以降が対象で、Python 3.15向けの調整もこの版に入っている。
Cythonとは:PythonをC拡張モジュールに変換するコンパイラ
Cythonは、Pythonの文法にC言語の型宣言を足した言語であり、同時にその言語をC(またはC++)のソースへ変換するコンパイラの名前でもあります。変換されたCソースをCコンパイラがビルドすると、Pythonからimportできる拡張モジュールになります。NumPyの乱数生成(numpy.random)、pandasの内部ライブラリ(pandas._libs)、scikit-learnの決定木、SciPyの特殊関数も、ソースには.pyxファイルが含まれています。
Pythonのコードが遅くなりやすいのは、変数の型が実行時まで決まらないためです。s += x * x - xという1行でも、CPythonは毎回xの型を調べ、整数か浮動小数点数かを判定し、結果を新しいオブジェクトとして確保します。Cythonでxとsをcdef doubleと宣言すると、この行はCの乗算・減算・加算に変換されます。速くなる理由は「コンパイルしたから」ではなく「型が決まったから」です。
Cythonの読み方とPyrexからの開発経緯
読み方は「サイソン」で、英語の発音記号は/ˈsaɪθɒn/です。Greg Ewingが開発したPyrexという先行言語をもとに、数式処理システムSageMathの開発者とXMLライブラリlxmlの開発者が分岐させ、2007年7月28日に公開したのが始まりです。ライセンスはApache License 2.0です。
CPython・PyPy・Numbaとの違い
名前が似ている「CPython(シーパイソン)」は、python.orgで配布されている標準のPython処理系そのものです。Cythonはその上で動く拡張モジュールを作る道具で、CPythonを置き換えるものではありません。
| 名前 | 種類 | コードの書き換え | 変換のタイミング |
|---|---|---|---|
| CPython | Pythonの標準処理系 | 不要 | 実行時に解釈(JITは試験的機能) |
| Cython | C拡張を作るコンパイラ | 型宣言を追加 | 事前にビルド |
| PyPy | 別のPython処理系 | 不要 | 実行時にJIT |
| Numba | 関数単位のJITライブラリ | デコレータを付ける | 初回呼び出し時 |
NumPy配列を扱う関数を手早く速くしたいだけなら、ビルド工程の要らないNumbaとは?Pythonを高速化するJITコンパイラの使い方とインストールの方が導入は軽く済みます。Cythonが向くのは、Cのライブラリを呼びたいとき、ビルド済みの拡張モジュールとして配布したいとき、クラス(拡張型)ごと高速化したいときです。
Cythonのインストール:pip・condaとCコンパイラ
Cython本体はPyPIとconda-forgeで配布されています。PyPIのCythonのページでは、3.3.0にCPython 3.9〜3.15向けのビルド済みwheelが用意されており、多くの環境ではソースからのビルドなしで入ります。
pip install cython
# Anaconda/Miniconda の場合
conda install -c conda-forge cython
# バージョン確認
cython --version
# Cython version 3.3.0
公式サイトcython.orgのトップページは、2026年11月2日の時点で最新安定版を「3.2.9(2026-07-24)」と表示しています。PyPIでは3.3.0が公開済みなので、版の確認はPyPIかpip index versions cythonで行ってください。
OSごとに必要なCコンパイラ
Cython自体はCソースを出力するところまでしか担当しません。出力されたCソースを拡張モジュールにするには、OSのCコンパイラが必要です。Cython 3.1以降の生成コードは、C99に対応したコンパイラを前提にしています。
| OS | 用意するもの | 入れ方 |
|---|---|---|
| Windows | Microsoft C++ Build Tools(MSVC) | Visual Studio Installerで「C++によるデスクトップ開発」 |
| macOS | Xcode Command Line Tools(clang) | xcode-select --install |
| Linux | gccとPythonのヘッダ | apt install build-essential python3-devなど |
Cythonの使い方:.pyxを書いてビルドするまで
Cythonのコードは拡張子.pyxのファイルに書き、ビルドしてからimportします。ビルドの方法は、パッケージとして配布するかどうかで選びます。
cythonizeとsetup.pyでその場でビルドする
1ファイルを試すだけなら、cythonize -i typed.pyxでカレントディレクトリに拡張モジュールができます。複数の.pyxをまとめて変換したいときや、コンパイラのオプションを指定したいときは、setup.pyでcythonize()を呼びます。
# setup.py
from setuptools import setup
from Cython.Build import cythonize
setup(ext_modules=cythonize(["typed.pyx"], annotate=True))
# 実行(カレントディレクトリに .so / .pyd ができる)
# python setup.py build_ext --inplace
pyproject.tomlでパッケージとして配布する
配布するパッケージにする場合、ビルド設定はpyproject.tomlだけで書けます。[tool.setuptools]のext-modulesはsetuptools 74.1.0で追加された項目で、setuptools側では試験的機能(EXPERIMENTAL)と明記されています。ビルド依存にCythonを入れておくと、.pyxが自動でCへ変換されます。
[build-system]
requires = ["setuptools>=74.1", "Cython>=3.1"]
build-backend = "setuptools.build_meta"
[project]
name = "fastcalc"
version = "0.1.0"
[tool.setuptools]
ext-modules = [
{name = "fastcalc", sources = ["src/fastcalc.pyx"]}
]
このディレクトリでpip install .を実行すると、wheelのビルドからインストールまで進み、import fastcalcで読み込めるようになります。
pyximportとJupyterの%%cythonで試す
配布しない実験用のコードなら、ビルド設定を書かずに済む方法が2つあります。pyximportは、importした時点で.pyxを自動でビルドします。
import pyximport
pyximport.install(language_level=3)
import typed # 同じディレクトリの typed.pyx がビルドされて読み込まれる
Jupyter NotebookやJupyterLabでは、%load_ext Cythonを実行したあと、セルの先頭に%%cythonと書くとそのセルがCythonとしてビルドされます。%%cython -aにすると、後述するannotateの結果がセルの下に表示されます。
pure Pythonモードで.pyのまま型を付ける
cimportやcdefを使わず、Pythonの型注釈で型を宣言する書き方を「pure Pythonモード」と呼びます。ファイルは.pyのままなので、Cythonでビルドしなければ通常のPythonとしても動きます。
# puremode.py
import cython
@cython.cfunc
@cython.inline
def f(x: cython.double) -> cython.double:
return x * x - x
def integrate_f(a: cython.double, b: cython.double, N: cython.long):
s: cython.double = 0.0
dx: cython.double = (b - a) / N
i: cython.long
for i in range(N):
s += f(a + i * dx)
return s * dx
このファイルをcythonize(["puremode.py"])でビルドすると、後述の実測で.pyx版とほぼ同じ速度が出ました。既存のPythonコードに少しずつ型を足していく場合や、mypyなどの型チェッカーを併用したい場合は、こちらが扱いやすくなります。C整数にしたい変数はintではなくcython.intで注釈します。公式のpure Pythonモードの解説のとおり、ただのintはPythonの整数のまま扱われます。
def・cdef・cpdefの違いと例外の扱い
Cythonの関数定義は3種類あります。違いは「Pythonから呼べるか」と「Cの速度で呼べるか」です。
| 定義 | Pythonから呼ぶ | Cython内から呼ぶ | 主な用途 |
|---|---|---|---|
def |
できる | Python関数として呼ぶ(遅い) | モジュールの入口 |
cdef |
できない | C関数として呼ぶ(速い) | 内部の計算関数 |
cpdef |
できる | C関数として呼ぶ(速い) | 両方から使う関数 |
cdef関数をPythonから呼ぶと、AttributeError: module 'kinds' has no attribute 'c_only'になります。cpdefは同じ処理のC版とPythonラッパーの2つを生成するので、Pythonからも呼べます。外部に公開する関数をdef、内部で何度も呼ぶ関数をcdefにして、両方から呼ぶ必要が出たものだけcpdefにすると整理しやすくなります。
Cython 3で変わった例外の伝播とnoexcept
Cython 3.0(2023-07-17)から、externでないcdef関数は、戻り値がC型でも内部で発生した例外を呼び出し元へ伝えるのが既定になりました。0.29系では、except宣言を書き忘れると例外が握りつぶされていました。
cdef int check(int x) except -1:
if x < 0:
raise ValueError("negative")
return x
cdef int noexc(int x) noexcept:
if x < 0:
raise ValueError("negative")
return x
負の値を渡すと、checkはValueErrorを呼び出し元へ伝えます。noexceptを付けたnoexcは、標準エラーにException ignored in: 'kinds.noexc'と出したうえで0を返し、処理を続けます。noexceptは例外確認の分岐が消えるぶん速くなりますが、例外が起こりえない関数にだけ付けてください。0.29系から移行したコードで当面の挙動を変えたくないときは、ディレクティブlegacy_implicit_noexcept=Trueで旧来の動作に戻せます。
型宣言でどれだけ速くなるか:Python 3.15での段階別の実測
同じ計算を「Python」「型を付けずにCythonでビルド」「.pyxで型を宣言」「pure Pythonモードで型を宣言」の4通りで書き、実行時間を比べました。計算は、区間[0, 2]を1,000万分割したx*x - xの数値積分です。
測定環境:Intel Core i9-9880H(8コア16スレッド)、macOS、Python 3.15.0(Homebrew。2026年11月2日時点の最新は10月25日公開の3.15.2)、Cython 3.3.0、NumPy 2.5.4、Apple clang 21。timeit.repeatをnumber=1・repeat=7で回した最小値です。速度比はこの処理と環境での値で、ほかのプログラムが動いていると数十パーセント単位でぶれます。表は3回測ったうち最後の回の値で、3回を通すと型宣言版のPython比は96〜132倍、後述の境界確認を外した効果は3.5〜11%の幅でした。
# typed.pyx
cimport cython
cdef double f(double x) noexcept:
return x * x - x
def integrate_f(double a, double b, long N):
cdef double s = 0.0
cdef double dx = (b - a) / N
cdef long i
for i in range(N):
s += f(a + i * dx)
return s * dx
| 書き方 | 実行時間 | Python比 |
|---|---|---|
| Python(そのまま) | 2.420秒 | 1倍 |
| Cython・型なし(.pyxに同じコード) | 2.462秒 | 約1.0倍 |
Cython・.pyxで型宣言 |
0.0201秒 | 約120倍 |
| Cython・pure Pythonモードで型宣言 | 0.0195秒 | 約124倍 |
4通りとも結果は0.6666664666666611で一致しました。型なし版は、Pythonと交互に5回ずつ測り直しても、Pythonが2.24〜2.73秒、型なし版が2.48〜2.62秒で、速くなったとは言えませんでした。同じ機械でPython 3.14.7(Cython 3.3.0)も交互に5回ずつ測り直したところ、Pythonが2.77〜3.03秒、型なし版が2.67〜2.84秒で、差は約4%でした。型を付けないビルドで得られる差は、どちらの版でも計測のぶれの範囲に収まります。Cythonを使うなら、型宣言は前提と考えてください。
annotate(cython -a)でPython C-APIを呼ぶ行を探す
どの行に型が足りないかは、cython -a typed.pyx(またはcythonize(..., annotate=True))が出力するHTMLで確認できます。公式のannotateの説明のとおり、白い行は純粋なCに変換された行、黄色い行はPythonの内部API(C-API)を呼んでいる行で、黄色が濃いほど呼び出しが多いことを示します。行をクリックすると生成されたCコードが展開されます。
上の2つを比べると、型なし版ではfor i in range(N):の行がスコア25、s += f(a + i * dx)の行がスコア26でした。型付け版ではこの2行がどちらもスコア0(白)になります。型付け版でもdx = (b - a) / Nの行にスコア5の薄い黄色が残るのは、ゼロ除算の確認コードが入るためです。cdivisionの既定値はFalseなので、Nが0にならないことを確かめたうえで@cython.cdivision(True)を付けると消せます。
NumPy配列を速く扱う:typed memoryview
NumPy配列をCythonの関数に渡すときは、typed memoryviewという型で受けます。double[::1]は「C連続に並んだdoubleの1次元配列」を表し、要素へのアクセスがPythonを経由しない配列アクセスになります。
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def total(double[::1] arr):
cdef double s = 0.0
cdef Py_ssize_t i
for i in range(arr.shape[0]):
s += arr[i]
return s
boundscheck(False)はインデックスが範囲内かの確認を、wraparound(False)はarr[-1]のような負のインデックスの処理を省きます。Cython 3.3.0ではどちらも既定値がTrue(確認する)です。公式のNumPyチュートリアルは、確認を外したまま範囲外にアクセスすると、よくてプログラムのクラッシュ、悪ければデータの破壊になると注意しています。範囲外アクセスをしないことが確実なループにだけ付けてください。
np.random.default_rng(0).random(10_000_000)で作った、C連続なfloat64配列の合計を比べた結果が次の表です。
| 書き方 | 実行時間 |
|---|---|
| Pythonのforループ | 3.462秒 |
| Cython・型なし | 3.401秒 |
| Cython・typed memoryview(確認あり) | 0.0246秒 |
| Cython・typed memoryview(確認なし) | 0.0219秒 |
NumPyのarr.sum() |
0.0088秒 |
memoryview版はPythonのループより約158倍速くなりました。境界確認を外した効果は0.0246秒から0.0219秒で約1割です。一方、NumPyのsum()には2倍以上の差で届きませんでした。NumPyの組み込み関数はもともとCで実装されているため、同じ処理をCythonで書き直しても上回れるとは限りません。Cythonの出番は、NumPyの関数を組み合わせても書けない処理です。前の要素の結果に依存する漸化式のループや、要素ごとに条件分岐が変わるループがこれに当たります。NumPy自体の基本はNumPyとは?読み方・インストール・基本的な使い方をPythonで解説(NumPy 2.5対応)で扱っています。
拡張型(cdef class)で属性を固定したクラスを作る
cdef classで定義したクラスは「拡張型」と呼ばれ、属性の型と数がコンパイル時に固定されます。属性はC構造体のメンバーとして持つため、Pythonのクラスのように__dict__を引いて属性を探す処理が要りません。
# shapes.pyx
cdef class Rect:
cdef public double width # Pythonから読み書きできる
cdef readonly double height # Pythonからは読み取りのみ
cdef double scale # Pythonからは見えない
def __init__(self, double w, double h):
self.width = w
self.height = h
self.scale = 1.0
cpdef double area(self):
return self.width * self.height * self.scale
Rect(3, 4).area()は12.0を返します。Python側から触ったときの挙動は、通常のクラスと次の3点で違いました。
readonlyのheightに代入するとAttributeError: attribute 'height' of 'shapes.Rect' objects is not writable- 修飾子なしの
scaleを読むとAttributeError: 'shapes.Rect' object has no attribute 'scale' - 宣言していない属性
colorを足そうとするとno __dict__ for setting new attributesで拒否される
属性の公開範囲は公式の拡張型の解説にあるとおり、既定ではPythonから見えず、publicかreadonlyを付けたものだけが公開されます。実行中に属性を足すようなクラス(設定オブジェクトなど)は拡張型に向きません。粒子や格子点のように、同じ形のオブジェクトを大量に作って計算する部分に使います。
Cのライブラリ・C++をCythonから呼び出す
公式サイトが「外部のCライブラリをラップするのに最適な言語」と打ち出しているとおり、既存のCやC++のコードをPythonから使えるようにする用途もCythonの主要な使い道です。
cdef externでCのヘッダの関数を呼ぶ
cdef extern fromにヘッダ名を書き、使う関数の宣言を並べると、Cの関数をPythonを経由せずに呼べます。標準ライブラリの主要な関数は、Cythonが同梱する宣言ファイル(libc.mathなど)をcimportするだけで使えます。
# fastcalc.pyx
cdef extern from "math.h":
double sqrt(double x) nogil
from libc.math cimport hypot
def norm(double x, double y):
return sqrt(x * x + y * y), hypot(x, y)
fastcalc.norm(3.0, 4.0)は(5.0, 5.0)を返します。自作のCライブラリを呼ぶときは、ExtensionのsourcesにCファイルを加えるか、libraries・library_dirsでビルド済みのライブラリをリンクします。
language=c++とlibcppでC++の標準ライブラリを使う
C++としてビルドするには、ファイル先頭に# distutils: language = c++と書くか、Extensionにlanguage="c++"を渡します。std::vectorなどの宣言はlibcppパッケージに同梱されています。書き方は公式のC++ラップの解説にまとまっています。
# distutils: language = c++
from libcpp.vector cimport vector
def squares(int n):
cdef vector[int] v
cdef int i
for i in range(n):
v.push_back(i * i)
return v
squares(5)は[0, 1, 4, 9, 16]を返し、型はPythonのlistでした。vectorをdef関数から返すと、Cythonがリストへ自動で変換します。大きな配列を何度も受け渡す場合はこの変換で要素がコピーされるので、memoryviewで受け渡す設計を検討してください。
prangeによる並列処理とGIL
通常のCPythonでは、threadingで複数スレッドを立ててもGIL(グローバルインタプリタロック)があるため、Pythonコードの計算は同時に1スレッドしか進みません。Cythonではcython.parallel.prangeを使うと、OpenMPのスレッドプールにループの反復を分配できます。GIL付きのCPythonで実際に並列に動かすには、nogil=Trueでループ全体をGILの外に出す必要があります。
# par.pyx
from cython.parallel cimport prange
cimport cython
@cython.boundscheck(False)
@cython.wraparound(False)
def psum(double[::1] arr):
cdef double s = 0.0
cdef Py_ssize_t i
for i in prange(arr.shape[0], nogil=True):
s += arr[i]
return s
s += ...のようにループ内で加算している変数は、Cythonがスレッドごとの部分和を合算する「リダクション」として扱います。前章と同じ1,000万要素の合計を5回測った最小値で、逐次版の0.0214秒がprange版では0.0045秒(約4.8倍)になりました。同じ測定を3回繰り返すと、倍率は3.1〜4.8倍の幅でぶれました。合計のように1要素あたりの計算が軽い処理では、8コア16スレッドでもコア数どおりには伸びません。足し合わせる順序が変わるため、結果は逐次版と最後の数桁が異なります(4999281.5621345835に対して4999281.562134152)。
macOS標準のApple clangでOpenMPを有効にする
OpenMPを有効にするにはコンパイラに-fopenmpを渡しますが、macOS標準のApple clangはこのオプションを受け付けず、clang: error: unsupported option '-fopenmp'で止まります。Homebrewでlibompを入れ、プリプロセッサ経由でOpenMPを有効にしてリンクします。
# setup_par.py(macOS・Intel版Homebrewのパス)
from setuptools import setup, Extension
from Cython.Build import cythonize
omp = "/usr/local/opt/libomp" # Apple シリコンは /opt/homebrew/opt/libomp
ext = Extension("par", ["par.pyx"],
extra_compile_args=["-Xpreprocessor", "-fopenmp", f"-I{omp}/include"],
extra_link_args=[f"-L{omp}/lib", "-lomp"])
setup(ext_modules=cythonize([ext]))
Linuxのgccでは、extra_compile_argsとextra_link_argsの両方に-fopenmpを渡します。WindowsのMSVCはextra_compile_argsに/openmpを渡すだけで、リンク側のオプションは要りません。
フリースレッド版Pythonへの対応状況
GILを持たないフリースレッド版CPythonには、Cython 3.1から対応しています。モジュールがスレッド安全であると宣言するには、ディレクティブfreethreading_compatible=Trueを付けます。付けないモジュールを読み込むと、フリースレッド版のPythonはGILを有効に戻して動きます。3.3.0ではprange()をGILを外さずに使う試験的な機能が入りました。並列に動くのはフリースレッド版だけで、公式の並列処理の解説は「very experimental」としたうえで、Pythonオブジェクトをスレッド安全に扱うのは利用者の責任だと注意しています。CPythonのJITやフリースレッド版の実測はPython 3.14のJITコンパイラとは?有効化の手順と3.15.0までの実測、フリースレッド版と新機能にまとめています。
Cythonのビルドで出る主なエラーと対処
Cythonでつまずく箇所の多くは、Cythonの文法ではなくCコンパイラとヘッダの準備です。エラーメッセージから原因を引けるよう、出やすいものを並べます。
| メッセージ(抜粋) | 原因 | 対処 |
|---|---|---|
Microsoft Visual C++ 14.0 or greater is required |
WindowsにMSVCが無い | Microsoft C++ Build Toolsを入れる |
'numpy/arrayobject.h' file not found |
NumPyのヘッダの場所が渡っていない | include_dirs=[numpy.get_include()] |
unsupported option '-fopenmp' |
Apple clangがOpenMP非対応 | libomp+-Xpreprocessor |
has no attribute 'c_only' |
cdef関数をPythonから呼んだ |
cpdefかdefにする |
Windowsのメッセージは、setuptoolsがMSVCを見つけられないときに出すもので、Cythonの不具合ではありません。cimport numpyを使う.pyxは、cythonize(["npc.pyx"])だけではCコンパイルの段階でfatal error: 'numpy/arrayobject.h' file not foundになりました。NumPyのget_include()の説明にある形でヘッダの場所を渡すと通ります。
from setuptools import setup, Extension
from Cython.Build import cythonize
import numpy
ext = Extension("npc", ["npc.pyx"], include_dirs=[numpy.get_include()])
setup(ext_modules=cythonize([ext]))
ビルドは通るのに速くならない場合は、前述のannotateで黄色い行を探します。ループ変数・累積用の変数・引数のどれかに型が無いことがほとんどです。pip install .で一度インストールしたモジュールをpyximportで試し直すと、インストール済みの古い方が先に読み込まれることがあります。書き換えが反映されないときはpip uninstallしてから試してください。
VS CodeでCythonを書くための拡張機能と設定
VS Codeは.pyxを標準では認識しないため、拡張機能を入れます。Marketplaceで「cython」と検索して上位に出るのは次の3つです(2026年11月2日にMarketplaceの検索APIで取得した値)。
| 拡張機能(ID) | できること | 最終更新 | インストール数 |
|---|---|---|---|
| Cython(tcwalther.cython) | 構文の色分け | 2016-05 | 約21.9万 |
| Language-Cython(guyskk.language-cython) | 構文の色分け | 2023-12 | 約13.4万 |
| Cython VSCode(ktnrg45.vscode-cython) | 構文チェック・定義へ移動 | 2024-03 | 約5.1万 |
色分けだけなら上の2つのどちらかで足ります。cimport先の定義へジャンプしたい、構文エラーを保存前に知りたい場合はCython VSCodeを選びます。ただしCython VSCodeのリポジトリ(ktnrg45/vs-code-cython)はアーカイブ済みで、最後の更新は2024年3月です。Cython 3.3で増えたパターンマッチなどの構文は、拡張機能のエラー表示だけで判断せず、実際にビルドして確かめてください。
Python拡張(Pylance)の補完や型チェックは.py向けで、.pyxには効きません。補完を効かせたい部分はpure Pythonモードの.pyで書く方が実用的です。ビルドは統合ターミナルでpython setup.py build_ext --inplaceを実行し、annotateのHTMLはソースと同じディレクトリにできる.htmlをブラウザで開いて確認します。
Cython 3系の主な変更点(3.0〜3.3)
0.29系の解説記事をもとにコードを書くと、既定値の違いでつまずきます。3.0以降の主な変更は次のとおりです。
| 版(公開日) | 主な変更 |
|---|---|
| 3.0.0(2023-07-17) | cdef関数の例外伝播が既定に・noexcept追加 |
| 3.1.0(2025-05-08) | フリースレッド版CPython対応・language_level=3が既定 |
| 3.2.0(2025-11-05) | フリースレッド版とLimited APIの対応を拡充 |
| 3.3.0(2026-08-22) | PEP 634のパターンマッチ・except*(Python 3.11以降)・Python 3.15への対応 |
3.3.0の変更履歴には、Python 3.15とそのLimited APIに合わせた変更が入った一方で、フリースレッド版向けの安定ABI(abi3t)はまだ対象外と書かれています。3.1以降はlanguage_level=3が既定なので、ファイル先頭の# cython: language_level=3は省略しても同じ動作になります。古いCythonでもビルドする可能性があるなら書いておくと安全です。各版の変更の全文はCython公式の変更履歴(Changelog)で確認できます。Python 3.15本体の変更点はPython 3.15の新機能|遅延インポートとUTF-8既定化、3.14から上げる手順で扱っています。
Cythonを使わない方がよい場面
Cythonを使うと、開発機・CI、そしてビルド済みwheelが無い環境の利用者に、Cコンパイラとビルド工程が必要になります。次のどれかに当たるなら、先に別の手段を検討してください。
- NumPyやpandasの1命令で書ける処理:配列の合計はNumPyの方が2倍以上速かった。まずベクトル化を試す。
- 通信やファイル読み書きの待ちが中心の処理:CPUの計算が速くなっても待ち時間は減らない。
asyncioやスレッドで待ちを重ねる方が効く。 - 型を宣言する手間をかけられないコード:Python 3.14.7・3.15.0のどちらでも、型なしのビルドでは速くならなかった。Numbaが対応する数値計算なら、デコレータで済む方法を先に比べる。
- 配布先のOSとPythonの版が多いライブラリ:OS×Pythonの版ごとにwheelのビルドが必要になり、配布作業が増える。
処理全体のうち、実際に時間を使っているのはごく一部の関数であることがほとんどです。python -m cProfile -s cumtime main.pyで時間のかかっている関数を特定し、そこだけを.pyxに切り出すのが基本の進め方です。Cython・Codon・Mojoを同じ処理で比べた速度はCython・Codon・Mojo実測比較|Pythonコードは何倍速くなるかで確認できます。Pythonで組んだ業務システムの処理速度を、プロファイリングから設計の見直しまで含めて改善したい場合は、フルスクラッチ開発の範囲でご相談いただけます。
よくある質問
Cythonの読み方は?
「サイソン」と読みます。英語の発音記号は/ˈsaɪθɒn/です。Pythonの標準処理系であるCPython(シーパイソン)とは別のソフトウェアです。
CythonとPythonの違いは何ですか?
Pythonは言語とその処理系(CPython)で、コードを実行時に解釈します。CythonはPythonの文法にCの型宣言を足した言語と、それをC拡張モジュールにするコンパイラです。Pythonのコードの多くはそのままCythonでもビルドできますが、型を宣言しないと、今回の計測ではほとんど速くなりませんでした。
cpdefとは何ですか?
Cの速度で呼べる関数と、Pythonから呼べるラッパーを同時に生成する関数定義です。Pythonからはdefと同じように呼べ、Cython内部からはC関数として直接呼ばれます。拡張型のメソッドでは、Python側で上書きされていないかの確認が入るぶん、cdefより負担がわずかに増えることがあります。
CythonでNumPyの処理は速くなりますか?
NumPyの関数1つで書ける処理は、Cythonで書き直しても速くなるとは限りません。要素ごとに条件が変わるループなど、NumPyで書きにくい処理をtyped memoryview(double[::1]など)で書いたときに効果が出ます。
VS CodeでCythonのコード補完は使えますか?
Python拡張のPylanceは.pyxを解析しないため、補完は限定的です。構文チェックと定義へのジャンプはCython VSCode(ktnrg45.vscode-cython)で使えますが、更新は2024年3月で止まっています。補完を重視するなら、pure Pythonモードで.pyとして書く方法があります。