# 使用更快靜態類型代碼
> 原文: [http://docs.cython.org/en/latest/src/quickstart/cythonize.html](http://docs.cython.org/en/latest/src/quickstart/cythonize.html)
Cython 是一個 Python 編譯器。這意味著它可以在不進行更改的情況下編譯普通的 Python 代碼(除了一些尚未支持的語言功能的一些明顯例外,請參閱 [Cython 限制](../userguide/limitations.html#cython-limitations) )。但是,對于影響性能的關鍵代碼,添加靜態類型聲明通常很有用,因為它們將允許 Cython 脫離 Python 代碼的動態特性并生成更簡單,更快速的 C 代碼 - 有時會快幾個數量級。
但必須注意,類型聲明可以使源代碼更加冗長,從而降低可讀性。因此,不鼓勵在沒有充分理由的情況下使用它們,例如基準測試證明它們在性能關鍵部分確實使代碼更快。通常情況下,正確使用的一些類型會有很長的路要走。
所有 C 類型都可用于類型聲明:整數和浮點類型,復數,結構,聯合和指針類型。 Cython 可以在分配時自動和正確地轉換類型。這還包括 Python 的任意大小整數類型,其中轉換為 C 類型時溢出的值將在運行時引發 Python `OverflowError`。 (但是,在進行算術運算時,它不會檢查溢出。)在這種情況下,生成的 C 代碼將正確且安全地處理 C 類型的平臺相關大小。
類型通過 cdef 關鍵字聲明。
## 指定變量類型
考慮以下純 Python 代碼:
```py
def f(x):
return x ** 2 - x
def integrate_f(a, b, N):
s = 0
dx = (b - a) / N
for i in range(N):
s += f(a + i * dx)
return s * dx
```
在 Cython 中簡單地編譯它只能提供 35%的加速。這比沒有好,但添加一些靜態類型可以產生更大的差異。
使用其他類型聲明,這可能如下所示:
```py
def f(double x):
return x ** 2 - x
def integrate_f(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
```
由于迭代器變量`i`是用 C 語法定義的,因此 for 循環將被編譯為純 C 代碼。鍵入`a`,`s`和`dx`非常重要,因為它們涉及 for 循環中的算術運算;鍵入`b`和`N`會產生較小的差異,但在這種情況下,要保持一致并輸入整個函數并不是一件額外需要做的工作。
這導致純 Python 版本的速度提高了 4 倍。
## 指定函數類型
Python 函數調用可能很昂貴 - 在 Cython 中是雙倍的,因為可能需要轉換到 Python 對象和從 Python 對象進行調用。在上面的示例中,假設參數在 `f()`內部和調用它時都是 C 中的double類型,但是`float`類型必須為參數構造一個 Python 對象才能傳遞它。
因此,Cython 提供了聲明 C 風格函數的語法,即 cdef 關鍵字:
```py
cdef double f(double x) except? -2:
return x ** 2 - x
```
通常應該添加某種形式的 except-modifier,否則 Cython 將無法傳播函數(或它調用的函數)中引發的異常。 `except? -2`表示如果返回`-2`將檢查錯誤(盡管`?`表示`-2`也可以用作有效返回值)。或者,較慢的`except *`始終是安全的。如果函數返回 Python 對象或者保證在函數調用中不會引發異常,則可以省略 except 子句。
cdef 的副作用是 Python 空間不再提供該函數,因為 Python 不知道如何調用它。也無法再在運行時更改`f()`。
使用`cpdef`關鍵字而不是`cdef`,還會創建一個 Python 包裝器,以便該函數可以從 Cython(快速,直接傳遞類型值)和 Python(包裝 Python 對象中的值)中獲得。事實上,`cpdef`不僅提供了一個 Python 包裝器,它還安裝了邏輯,允許方法被 python 方法覆蓋,即使從 cython 中調用也是如此。與`cdef`方法相比,這確實增加了很小的開銷。
加速:超過純 Python 的 150 倍。
## 確定所添加類型的位置
因為靜態類型通常是提高速度的關鍵所在,所以初學者往往傾向于所見之處指定各種變量的類型。這降低了可讀性和靈活性,甚至可以降低速度(例如,通過添加不必要的類型檢查,轉換或緩慢的緩沖區解包)。另一方面,忘記鍵入關鍵循環變量很容易破壞性能。幫助完成此任務的兩個基本工具是分析和注釋。分析應該是任何優化工作的第一步,并且可以告訴您在哪里花費時間。 Cython 的注釋可以告訴你為什么你的代碼需要時間。
使用`-a`開關到`cython`命令行程序(或跟隨 Sage 筆記本的鏈接)會導致 Cython 代碼的 HTML 報告與生成的 C 代碼交錯。線條根據“類型”的級別著色 - 白線轉換為純 C,而需要 Python C-API 的線條為黃色(因為它們轉化為更多的 C-API 交互,因此更暗)。轉換為 C 代碼的行在前面有一個加號(`+`),可以單擊以顯示生成的代碼。
當優化速度函數以及確定何時 [釋放 GIL](../userguide/external_C_code.html#nogil)時,此報告非常有用:通常,`nogil`塊可能只包含“白色”代碼。

請注意,Cython 根據其賦值(包括作為循環變量目標)推斷出局部變量的類型,這也可以減少在任何地方顯式指定類型的需要。例如,將`dx`聲明為 double 類型是不必要的,就像在最后一個版本中聲明`s`的類型一樣(其中`f`的返回類型已知為 C 語言的double類型。)一個值得注意的例外然而,算術表達式中使用的是整數類型,因為 Cython 無法確保不會發生溢出(因此在需要 Python 的 bignums 時會回退到`object`)。要允許推斷 C 整數類型,請將`infer_types` [指令](../userguide/source_files_and_compilation.html#compiler-directives) 設置為`True`。對于熟悉此語言功能的讀者,此指令的工作類似于 C ++中的`auto`關鍵字。減少輸入所有內容的需求可能會有很大幫助,但也可能導致意外。特別是如果一個人不熟悉 c 類型的算術表達式。這些可以在[中找到](https://www.eskimo.com/~scs/cclass/int/sx4cb.html)[的快速概述。](https://www.eskimo.com/~scs/cclass/int/sx4cb.html)_
- Cython 3.0 中文文檔
- 入門
- Cython - 概述
- 安裝 Cython
- 構建 Cython 代碼
- 通過靜態類型更快的代碼
- Tutorials
- 基礎教程
- 調用 C 函數
- 使用 C 庫
- 擴展類型(又名.cdef 類)
- pxd 文件
- Caveats
- Profiling
- Unicode 和傳遞字符串
- 內存分配
- 純 Python 模式
- 使用 NumPy
- 使用 Python 數組
- 進一步閱讀
- 相關工作
- 附錄:在 Windows 上安裝 MinGW
- 用戶指南
- 語言基礎
- 擴展類型
- 擴展類型的特殊方法
- 在 Cython 模塊之間共享聲明
- 與外部 C 代碼連接
- 源文件和編譯
- 早期綁定速度
- 在 Cython 中使用 C ++
- 融合類型(模板)
- 將 Cython 代碼移植到 PyPy
- Limitations
- Cython 和 Pyrex 之間的區別
- 鍵入的內存視圖
- 實現緩沖協議
- 使用并行性
- 調試你的 Cython 程序
- 用于 NumPy 用戶的 Cython
- Pythran 作為 Numpy 后端