---
title: "Cythonとは？読み方・使い方と型宣言の効果を実測【Cython 3.3・Python 3.15】"
url: "https://www.issoh.co.jp/tech/details/3699/"
published: 2024-10-01
updated: 2026-11-02
categories: ["Python"]
publisher: "株式会社一創"
---

# Cythonとは？読み方・使い方と型宣言の効果を実測【Cython 3.3・Python 3.15】

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コンパイラの使い方とインストール](/tech/details/3607/)の方が導入は軽く済みます。Cythonが向くのは、Cのライブラリを呼びたいとき、ビルド済みの拡張モジュールとして配布したいとき、クラス（拡張型）ごと高速化したいときです。

## Cythonのインストール：pip・condaとCコンパイラ

Cython本体はPyPIとconda-forgeで配布されています。[PyPIのCythonのページ](https://pypi.org/project/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モードの解説](https://cython.readthedocs.io/en/latest/src/tutorial/pure.html)のとおり、ただの`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の説明](https://cython.readthedocs.io/en/latest/src/quickstart/cythonize.html)のとおり、白い行は純粋な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チュートリアル](https://cython.readthedocs.io/en/latest/src/userguide/numpy%5Ftutorial.html)は、確認を外したまま範囲外にアクセスすると、よくてプログラムのクラッシュ、悪ければデータの破壊になると注意しています。範囲外アクセスをしないことが確実なループにだけ付けてください。

`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対応）](/tech/details/3124/)で扱っています。

## 拡張型（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`で拒否される

属性の公開範囲は[公式の拡張型の解説](https://cython.readthedocs.io/en/latest/src/userguide/extension%5Ftypes.html)にあるとおり、既定では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++ラップの解説](https://cython.readthedocs.io/en/latest/src/userguide/wrapping%5FCPlusPlus.html)にまとまっています。

```
# 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を外さずに使う試験的な機能が入りました。並列に動くのはフリースレッド版だけで、[公式の並列処理の解説](https://cython.readthedocs.io/en/latest/src/userguide/parallelism.html)は「very experimental」としたうえで、Pythonオブジェクトをスレッド安全に扱うのは利用者の責任だと注意しています。CPythonのJITやフリースレッド版の実測は[Python 3.14のJITコンパイラとは？有効化の手順と3.15.0までの実測、フリースレッド版と新機能](/tech/details/9409/)にまとめています。

## 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()の説明](https://numpy.org/doc/stable/reference/generated/numpy.get%5Finclude.html)にある形でヘッダの場所を渡すと通ります。

```
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）](https://cython.readthedocs.io/en/latest/src/changes.html)で確認できます。Python 3.15本体の変更点は[Python 3.15の新機能｜遅延インポートとUTF-8既定化、3.14から上げる手順](/tech/details/18312/)で扱っています。

## 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コードは何倍速くなるか](/tech/details/4267/)で確認できます。Pythonで組んだ業務システムの処理速度を、プロファイリングから設計の見直しまで含めて改善したい場合は、[フルスクラッチ開発](/service/system/fullscratch/)の範囲でご相談いただけます。

## よくある質問

### 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`として書く方法があります。

## 関連記事

- [Numbaとは？Pythonを高速化するJITコンパイラの使い方とインストール](/tech/details/3607/)
- [Cython・Codon・Mojo実測比較｜Pythonコードは何倍速くなるか](/tech/details/4267/)
- [NumPyとは？読み方・インストール・基本的な使い方をPythonで解説（NumPy 2.5対応）](/tech/details/3124/)
- [Python 3.15の新機能｜遅延インポートとUTF-8既定化、3.14から上げる手順](/tech/details/18312/)
- [Codonとは？Pythonを高速化するコンパイラの使い方とPythonとの違い【v0.20.4・AtCoder対応】](/tech/details/9061/)

---

出典: [Cythonとは？読み方・使い方と型宣言の効果を実測【Cython 3.3・Python 3.15】](<https://www.issoh.co.jp/tech/details/3699/>)（株式会社一創）
