# 源文件和編譯
> 原文: [http://docs.cython.org/en/latest/src/userguide/source_files_and_compilation.html](http://docs.cython.org/en/latest/src/userguide/source_files_and_compilation.html)
Cython 源文件名由模塊名稱后跟`.pyx`擴展名組成,例如名為 primes 的模塊將具有名為`primes.pyx`的源文件。
與 Python 不同,必須編譯 Cython 代碼。這發生在兩個階段:
> * A `.pyx`文件由 Cython 編譯為`.c`文件。
> * `.c`文件由 C 編譯器編譯為`.so`文件(或 Windows 上的`.pyd`文件)
一旦編寫了`.pyx`文件,就可以通過幾種方法將其轉換為擴展模塊。
以下小節介紹了構建擴展模塊的幾種方法,以及如何將指令傳遞給 Cython 編譯器。
## 從命令行編譯
有兩種從命令行編譯的方法。
* `cython`命令獲取`.py`或`.pyx`文件并將其編譯為 C / C ++文件。
* `cythonize`命令獲取`.py`或`.pyx`文件并將其編譯為 C / C ++文件。然后,它將 C / C ++文件編譯為可直接從 Python 導入的擴展模塊。
### 使用`cython`命令進行編譯
一種方法是使用 Cython 編譯器手動編譯它,例如:
```py
$ cython primes.pyx
```
這將生成一個名為`primes.c`的文件,然后需要使用適合您平臺的任何選項使用 C 編譯器編譯該文件以生成擴展模塊。有關這些選項,請查看官方 Python 文檔。
另一種可能更好的方法是使用 Cython 提供的 [`distutils`](https://docs.python.org/3/library/distutils.html#module-distutils "(in Python v3.7)") 擴展。這種方法的好處是它將提供平臺特定的編譯選項,就像一個精簡的自動工具。
### 使用`cythonize`命令進行編譯
使用您的選項和`.pyx`文件列表運行`cythonize`編譯器命令以生成擴展模塊。例如:
```py
$ cythonize -a -i yourmod.pyx
```
這將創建一個`yourmod.c`文件(或 C ++模式下的`yourmod.cpp`),對其進行編譯,并將生成的擴展模塊(`.so`或`.pyd`,具體取決于您的平臺)放在源文件旁邊以進行直接導入(`-i`建立“到位”)。 `-a`開關另外生成源代碼的帶注釋的 html 文件。
`cythonize`命令接受多個源文件和類似`**/*.pyx`的 glob 模式作為參數,并且還了解運行多個并行構建作業的常用`-j`選項。在沒有其他選項的情況下調用時,它只會將源文件轉換為`.c`或`.cpp`文件。傳遞`-h`標志以獲取支持選項的完整列表。
更簡單的命令行工具`cython`僅調用源代碼轉換器。
在手動編譯的情況下,如何編譯`.c`文件將根據您的操作系統和編譯器而有所不同。用于編寫擴展模塊的 Python 文檔應該包含系統的一些詳細信息。例如,在 Linux 系統上,它看起來可能類似于:
```py
$ gcc -shared -pthread -fPIC -fwrapv -O2 -Wall -fno-strict-aliasing \
-I/usr/include/python3.5 -o yourmod.so yourmod.c
```
(`gcc`需要有包含頭文件的路徑和要鏈接的庫的路徑。)
編譯后,將`yourmod.so`(Windows 的`yourmod.pyd`)文件寫入目標目錄,您的模塊`yourmod`可以像任何其他 Python 模塊一樣導入。請注意,如果您不依賴于`cythonize`或 distutils,您將不會自動受益于 CPython 為消除歧義而生成的特定于平臺的文件擴展名,例如 CPython 3.5 的常規 64 位 Linux 安裝上的`yourmod.cpython-35m-x86_64-linux-gnu.so`。
## 基本 setup.py
Cython 提供的 distutils 擴展允許您將`.pyx`文件直接傳遞到安裝文件中的`Extension`構造函數。
如果你有一個 Cython 文件要轉換為編譯擴展名,比如文件名`example.pyx`,關聯的`setup.py`將是:
```py
from distutils.core import setup
from Cython.Build import cythonize
setup(
ext_modules = cythonize("example.pyx")
)
```
要更全面地了解`setup.py`官方 [`distutils`](https://docs.python.org/3/library/distutils.html#module-distutils "(in Python v3.7)") 文檔。要編譯擴展以在當前目錄中使用,請使用:
```py
$ python setup.py build_ext --inplace
```
### 配置 C-Build
如果您在非標準位置包含文件,則可以將`include_path`參數傳遞給`cythonize`:
```py
from distutils.core import setup
from Cython.Build import cythonize
setup(
name="My hello app",
ext_modules=cythonize("src/*.pyx", include_path=[...]),
)
```
通常,提供 C 級 API 的 Python 包提供了一種查找必要包含文件的方法,例如,為 NumPy:
```py
include_path = [numpy.get_include()]
```
注意
使用內存視圖或使用`import numpy`導入 NumPy 并不意味著您必須添加 NumPy 包含文件的路徑。只有在使用`cimport numpy`時才需要添加此路徑。
盡管如此,您仍然會收到編譯器中的以下警告,因為 Cython 使用的是已棄用的 Numpy API:
```py
.../include/numpy/npy_1_7_deprecated_api.h:15:2: warning: #warning "Using deprecated NumPy API, disable it by " "#defining NPY_NO_DEPRECATED_API NPY_1_7_API_VERSION" [-Wcpp]
```
目前,這只是一個警告,你可以忽略。
如果需要指定編譯器選項,要鏈接的庫或其他鏈接器選項,則需要手動創建`Extension`實例(請注意,glob 語法仍可用于在一行中指定多個擴展名):
```py
from distutils.core import setup
from distutils.extension import Extension
from Cython.Build import cythonize
extensions = [
Extension("primes", ["primes.pyx"],
include_dirs=[...],
libraries=[...],
library_dirs=[...]),
# Everything but primes.pyx is included here.
Extension("*", ["*.pyx"],
include_dirs=[...],
libraries=[...],
library_dirs=[...]),
]
setup(
name="My hello app",
ext_modules=cythonize(extensions),
)
```
請注意,使用 setuptools 時,您應該在 Cython 之前導入它,因為 setuptools 可能會替換 distutils 中的`Extension`類。否則,兩人可能不同意這里使用的課程。
另請注意,如果使用 setuptools 而不是 distutils,則運行`python setup.py install`時的默認操作是創建一個壓縮的`egg`文件,當您嘗試從依賴項中使用它們時,這些文件無法與`pxd`文件一起用于`pxd`文件包。為防止這種情況,請在`setup()`的參數中包含`zip_safe=False`。
如果您的選項是靜態的(例如,您不需要調用`pkg-config`之類的工具來確定它們),您也可以使用文件開頭的特殊注釋塊直接在.pyx 或.pxd 源文件中提供它們。 :
```py
# distutils: libraries = spam eggs
# distutils: include_dirs = /opt/food/include
```
如果您導入多個定義庫的.pxd 文件,那么 Cython 會合并庫列表,因此這可以按預期工作(與其他選項類似,如上面的`include_dirs`)。
如果你有一些用 Cython 包裝的 C 文件,并且你想將它們編譯到你的擴展中,你可以定義 distutils `sources`參數:
```py
# distutils: sources = helper.c, another_helper.c
```
請注意,這些源將添加到當前擴展模塊的源列表中。在`setup.py`文件中將其拼寫如下:
```py
from distutils.core import setup
from Cython.Build import cythonize
from distutils.extension import Extension
sourcefiles = ['example.pyx', 'helper.c', 'another_helper.c']
extensions = [Extension("example", sourcefiles)]
setup(
ext_modules=cythonize(extensions)
)
```
`Extension`類有很多選項,可以在 [distutils 文檔](https://docs.python.org/extending/building.html)中找到更全面的解釋。要了解的一些有用選項是`include_dirs`,`libraries`和`library_dirs`,它們指定鏈接到外部庫時在哪里可以找到`.h`和庫文件。
有時這還不夠,你需要更精細的自定義 distutils `Extension`。為此,您可以提供自定義函數`create_extension`,以便在 Cython 處理源,依賴項和`# distutils`指令之后但在文件實際進行 Cython 化之前創建最終的`Extension`對象。該函數有 2 個參數`template`和`kwds`,其中`template`是作為 Cython 輸入的`Extension`對象,`kwds`是 [`dict`](https://docs.python.org/3/library/stdtypes.html#dict "(in Python v3.7)") ,應該使用所有關鍵字創建`Extension`。函數`create_extension`必須返回 2 元組`(extension, metadata)`,其中`extension`是創建的`Extension`,`metadata`是元數據,將在生成的 C 文件的頂部寫為 JSON。此元數據僅用于調試目的,因此您可以在其中放置任何內容(只要它可以轉換為 JSON)。默認功能(在`Cython.Build.Dependencies`中定義)是:
```py
def default_create_extension(template, kwds):
if 'depends' in kwds:
include_dirs = kwds.get('include_dirs', []) + ["."]
depends = resolve_depends(kwds['depends'], include_dirs)
kwds['depends'] = sorted(set(depends + template.depends))
t = template.__class__
ext = t(**kwds)
metadata = dict(distutils=kwds, module_name=kwds['name'])
return ext, metadata
```
如果您將字符串而不是`Extension`傳遞給`cythonize()`,`template`將是沒有來源的`Extension`。例如,如果執行`cythonize("*.pyx")`,`template`將為`Extension(name="*.pyx", sources=[])`。
舉個例子,這會將`mylib`作為庫添加到每個擴展名中:
```py
from Cython.Build.Dependencies import default_create_extension
def my_create_extension(template, kwds):
libs = kwds.get('libraries', []) + ["mylib"]
kwds['libraries'] = libs
return default_create_extension(template, kwds)
ext_modules = cythonize(..., create_extension=my_create_extension)
```
Note
如果你并行 Cython 化(使用`nthreads`參數),那么`create_extension`的參數必須是 pickleable。特別是,它不能是 lambda 函數。
### Cythonize 參數
函數`cythonize()`可以使用額外的參數來允許您自定義構建。
`Cython.Build.``cythonize`(_module_list_, _exclude=None_, _nthreads=0_, _aliases=None_, _quiet=False_, _force=False_, _language=None_, _exclude_failures=False_, _**options_)
將一組源模塊編譯為 C / C ++文件,并為它們返回 distutils Extension 對象的列表。
<colgroup><col class="field-name"> <col class="field-body"></colgroup>
| 參數: |
* **module_list** - 作為模塊列表,傳遞一個 glob 模式,一個 glob 模式列表或一個擴展對象列表。后者允許您通過常規 distutils 選項單獨配置擴展。您還可以傳遞具有 glob 模式作為其源的擴展對象。然后,cythonize 將解析模式并為每個匹配的文件創建擴展的副本。
* **排除** - 將 glob 模式作為`module_list`傳遞時,可以通過將某些模塊名稱傳遞給`exclude`選項來明確排除它們。
* **nthreads** - 并行編譯的并發構建數(需要`multiprocessing`模塊)。
* **別名** - 如果你想使用像`# distutils: ...`這樣的編譯器指令,但只能在編譯時(運行`setup.py`時)知道要使用哪些值,你可以使用別名和在調用 [`cythonize()`](#Cython.Build.cythonize "Cython.Build.cythonize") 時傳遞將這些別名映射到 Python 字符串的字典。例如,假設您要使用編譯器指令`# distutils: include_dirs = ../static_libs/include/`,但此路徑并不總是固定,您希望在運行`setup.py`時找到它。然后,您可以執行`# distutils: include_dirs = MY_HEADERS`,在`setup.py`中找到`MY_HEADERS`的值,將其作為字符串放入名為`foo`的 python 變量中,然后調用`cythonize(..., aliases={'MY_HEADERS': foo})`。
* **安靜** - 如果為 True,Cython 將不會在編譯期間打印錯誤和警告消息。
* **force** - 強制重新編譯 Cython 模塊,即使時間戳不表示需要重新編譯。
* **語言** - 要全局啟用 C ++模式,可以傳遞`language='c++'`。否則,將根據編譯器指令在每個文件級別確定。這僅影響基于文件名找到的模塊。傳入 [`cythonize()`](#Cython.Build.cythonize "Cython.Build.cythonize") 的擴展實例不會更改。建議使用編譯器指令`# distutils: language = c++`而不是此選項。
* **exclude_failures** - 對于廣泛的“嘗試編譯”模式,忽略編譯失敗并簡單地排除失敗的擴展,傳遞`exclude_failures=True`。請注意,這僅適用于編譯`.py`文件,這些文件也可以在不編譯的情況下使用。
* **注釋** - 如果`True`,將為每個編譯的`.pyx`或`.py`文件生成一個 HTML 文件。與普通的 C 代碼相比,HTML 文件指示了每個源代碼行中的 Python 交互量。它還允許您查看為每行 Cython 代碼生成的 C / C ++代碼。當優化速度函數以及確定何時 [釋放 GIL](external_C_code.html#nogil)時,此報告非常有用:通常,`nogil`塊可能只包含“白色”代碼。參見 [中的實例確定添加類型](../quickstart/cythonize.html#determining-where-to-add-types) 或 [Primes](../tutorial/cython_tutorial.html#primes)的位置。
* **compiler_directives** - 允許在`setup.py`中設置編譯器指令,如下所示:`compiler_directives={'embedsignature': True}`。參見 [編譯器指令](#compiler-directives) 。
|
| --- | --- |
## 包中的多個 Cython 文件
要自動編譯多個 Cython 文件而不顯式列出所有這些文件,可以使用 glob 模式:
```py
setup(
ext_modules = cythonize("package/*.pyx")
)
```
如果通過`cythonize()`傳遞它們,也可以在`Extension`對象中使用 glob 模式:
```py
extensions = [Extension("*", ["*.pyx"])]
setup(
ext_modules = cythonize(extensions)
)
```
### 分發 Cython 模塊
強烈建議您分發生成的`.c`文件以及 Cython 源,以便用戶可以安裝模塊而無需使用 Cython。
還建議在您分發的版本中默認不啟用 Cython 編譯。即使用戶安裝了 Cython,他/她可能也不想僅僅使用它來安裝模塊。此外,安裝的版本可能與您使用的版本不同,并且可能無法正確編譯您的源。
這只是意味著您附帶的`setup.py`文件將只是生成的 <cite>.c</cite> 文件中的正常 distutils 文件,對于我們將要使用的基本示例:
```py
from distutils.core import setup
from distutils.extension import Extension
setup(
ext_modules = [Extension("example", ["example.c"])]
)
```
通過更改擴展模塊源的文件擴展名,可以很容易地與`cythonize()`結合使用:
```py
from distutils.core import setup
from distutils.extension import Extension
USE_CYTHON = ... # command line option, try-import, ...
ext = '.pyx' if USE_CYTHON else '.c'
extensions = [Extension("example", ["example"+ext])]
if USE_CYTHON:
from Cython.Build import cythonize
extensions = cythonize(extensions)
setup(
ext_modules = extensions
)
```
如果您有許多擴展并希望避免聲明中的額外復雜性,您可以使用它們的正常 Cython 源聲明它們,然后在不使用 Cython 時調用以下函數而不是`cythonize()`來調整 Extensions 中的源列表:
```py
import os.path
def no_cythonize(extensions, **_ignore):
for extension in extensions:
sources = []
for sfile in extension.sources:
path, ext = os.path.splitext(sfile)
if ext in ('.pyx', '.py'):
if extension.language == 'c++':
ext = '.cpp'
else:
ext = '.c'
sfile = path + ext
sources.append(sfile)
extension.sources[:] = sources
return extensions
```
另一個選擇是使 Cython 成為系統的設置依賴項,并使用 Cython 的 build_ext 模塊作為構建過程的一部分運行`cythonize`:
```py
setup(
setup_requires=[
'cython>=0.x',
],
extensions = [Extension("*", ["*.pyx"])],
cmdclass={'build_ext': Cython.Build.build_ext},
...
)
```
如果要公開庫的 C 級接口以便其他庫從 cimport,請使用 package_data 來安裝`.pxd`文件,例如:
```py
setup(
package_data = {
'my_package': ['*.pxd'],
'my_package/sub_package': ['*.pxd'],
},
...
)
```
如果這些`.pxd`文件包含純粹的外部庫聲明,則它們不需要具有相應的`.pyx`模塊。
請記住,如果使用 setuptools 而不是 distutils,則運行`python setup.py install`時的默認操作是創建一個壓縮的`egg`文件,當您嘗試從依賴包中使用它們時,這些文件無法與`pxd`文件一起用于`pxd`文件。為防止這種情況,請在`setup()`的參數中包含`zip_safe=False`。
## 集成多個模塊
在某些情況下,將多個 Cython 模塊(或其他擴展模塊)鏈接到單個二進制文件中可能很有用,例如:將 Python 嵌入另一個應用程序時。這可以通過 CPython 的 inittab 導入機制來完成。
創建一個新的 C 文件以集成擴展模塊并將其添加到它:
```py
#if PY_MAJOR_VERSION < 3
# define MODINIT(name) init ## name
#else
# define MODINIT(name) PyInit_ ## name
#endif
```
如果您只定位 Python 3.x,只需使用`PyInit_`作為前綴。
然后,對于每個模塊,聲明其模塊 init 函數如下,將`some_module_name`替換為模塊的名稱:
```py
PyMODINIT_FUNC MODINIT(some_module_name) (void);
```
在 C ++中,將它們聲明為`extern C`。
如果您不確定模塊初始化函數的名稱,請參閱生成的模塊源文件并查找以`PyInit_`開頭的函數名稱。
接下來,在使用`Py_Initialize()`從應用程序代碼啟動 Python 運行時之前,需要使用`PyImport_AppendInittab()` C-API 函數在運行時初始化模塊,再次插入每個模塊的名稱:
```py
PyImport_AppendInittab("some_module_name", MODINIT(some_module_name));
```
這樣可以為嵌入式擴展模塊進行正常導入。
為了防止連接的二進制文件將所有模塊初始化函數導出為公共符號,如果在 C 編譯模塊 C 文件時定義了宏`CYTHON_NO_PYINIT_EXPORT`,則 Cython 0.28 及更高版本可以隱藏這些符號。
另請查看 [cython_freeze](https://github.com/cython/cython/blob/master/bin/cython_freeze) 工具。它可以生成必要的樣板代碼,用于將一個或多個模塊鏈接到單個 Python 可執行文件中。
## 用`pyximport` 編譯
為了在開發期間構建 Cython 模塊而不在每次更改后顯式運行`setup.py`,您可以使用`pyximport`:
```py
>>> import pyximport; pyximport.install()
>>> import helloworld
Hello World
```
這允許您在 Py??thon 嘗試導入的每個`.pyx`上自動運行 Cython。只有在沒有額外的 C 庫且不需要特殊的構建設置的情況下,才應該將它用于簡單的 Cython 構建。
也可以編譯正在導入的新`.py`模塊(包括標準庫和已安裝的軟件包)。要使用此功能,只需告訴`pyximport`:
```py
>>> pyximport.install(pyimport=True)
```
在 Cython 無法編譯 Python 模塊的情況下,`pyximport`將回退到加載源模塊。
請注意,建議不要讓`pyximport`在最終用戶端構建代碼,因為它會掛鉤到導入系統。滿足最終用戶的最佳方式是以[輪](https://wheel.readthedocs.io/)包裝格式提供預先構建的二進制包。
### 參數
函數`pyximport.install()`可以使用幾個參數來影響 Cython 或 Python 文件的編譯。
`pyximport.``install`(_pyximport=True_, _pyimport=False_, _build_dir=None_, _build_in_temp=True_, _setup_args=None_, _reload_support=False_, _load_py_module_on_import_failure=False_, _inplace=False_, _language_level=None_)
pyxinstall 的主要入口點。
調用此方法在元數據路徑中為單個 Python 進程安裝`.pyx`導入掛鉤。如果您希望在使用 Python 時安裝它,請將其添加到`sitecustomize`(如上所述)。
<colgroup><col class="field-name"> <col class="field-body"></colgroup>
| Parameters: |
* **pyximport** - 如果設置為 False,則不嘗試導入`.pyx`文件。
* **pyimport** - 您可以傳遞`pyimport=True`以在元路徑中安裝`.py`導入掛鉤。但請注意,它是相當實驗性的,對于某些`.py`文件和軟件包根本不起作用,并且由于搜索和編譯而會大大減慢您的導入速度。使用風險由您自己承擔。
* **build_dir** - 默認情況下,已編譯的模塊最終將位于用戶主目錄的`.pyxbld`目錄中。傳遞一個不同的路徑作為`build_dir`將覆蓋此。
* **build_in_temp** - 如果`False`,將在本地生成 C 文件。使用復雜的依賴項和調試變得更加容易。這主要可能會干擾同名的現有文件。
* **setup_args** - 分布參數的字典。見`distutils.core.setup()`。
* **reload_support** - 支持動態`reload(my_module)`,例如在 Cython 代碼更改后。當無法覆蓋先前加載的模塊文件時,該帳戶可能會出現附加文件`<so_path>.reloadNN`。
* **load_py_module_on_import_failure** - 如果`.py`文件的編譯成功,但后續導入由于某種原因失敗,請使用普通`.py`模塊而不是編譯模塊重試導入。請注意,這可能會導致在導入期間更改系統狀態的模塊出現不可預測的結果,因為第二次導入將在導入已編譯模塊失敗后系統處于的任何狀態下重新運行這些修改。
* **就地** - 在源文件旁邊安裝已編譯的模塊(Linux 的`.so`和 Mac 的`.pyd`)。
* **language_level** - 要使用的源語言級別:2 或 3.默認情況下,使用.py 文件的當前 Python 運行時的語言級別和`.pyx`文件的 Py2。
|
| --- | --- |
### 依賴性處理
由于`pyximport`內部不使用`cythonize()`,因此它當前需要不同的依賴設置。可以聲明您的模塊依賴于多個文件(可能是`.h`和`.pxd`文件)。如果您的 Cython 模塊名為`foo`,因此具有文件名`foo.pyx`,那么您應該在名為`foo.pyxdep`的同一目錄中創建另一個文件。 `modname.pyxdep`文件可以是文件名列表或“globs”(如`*.pxd`或`include/*.h`)。每個文件名或 glob 必須在單獨的行上。在決定是否重建模塊之前,Pyximport 將檢查每個文件的文件日期。為了跟蹤已經處理了依賴關系的事實,Pyximport 更新了“.pyx”源文件的修改時間。未來版本可能會做更復雜的事情,比如直接通知依賴關系的 distutils。
### 限制
`pyximport`不使用`cythonize()`。因此,不可能在 Cython 文件的頂部使用編譯器指令或將 Cython 代碼編譯為 C ++。
Pyximport 不會讓您控制 Cython 文件的編譯方式。通常默認值很好。如果你想用半-C,半 Cython 編寫你的程序并將它們構建到一個庫中,你可能會遇到問題。
Pyximport 不會隱藏導入過程生成的 Distutils / GCC 警告和錯誤。可以說,如果出現問題以及原因,這將為您提供更好的反饋。如果沒有出現任何問題,它會給你一種溫暖的模糊感覺,pyximport 確實按照預期重建你的模塊。
選項`reload_support=True`提供基本模塊重新加載支持。請注意,這將為每個構建生成一個新的模塊文件名,從而最終將多個共享庫隨時間加載到內存中。 CPython 對重新加載共享庫的支持有限,參見 [PEP 489](https://www.python.org/dev/peps/pep-0489/) 。
Pyximport 將您的`.c`文件和特定于平臺的二進制文件放入一個單獨的構建目錄,通常是`$HOME/.pyxblx/`。要將其復制回包層次結構(通常在源文件旁邊)以進行手動重用,可以傳遞選項`inplace=True`。
## 用`cython.inline` 編譯
也可以用類似于 SciPy 的`weave.inline`的方式編譯 Cython。例如:
```py
>>> import cython
>>> def f(a):
... ret = cython.inline("return a+b", b=3)
...
```
未綁定的變量會自動從周圍的本地和全局范圍中提取,并且編譯結果將被緩存以便有效地重復使用。
## 用 Sage 編譯
Sage 筆記本允許通過在單元格頂部鍵入`%cython`并對其進行評估來透明地編輯和編譯 Cython 代碼。 Cython 單元格中定義的變量和函數將導入到正在運行的會話中。有關詳細信息,請查看 [Sage 文檔](https://www.sagemath.org/doc/)。
您可以通過指定以下指令來定制 Cython 編譯器的行為。
## 使用 Jupyter 筆記本進行編譯
使用 Cython 可以在筆記本單元中編譯代碼。為此你需要加載 Cython 魔法:
```py
%load_ext cython
```
然后,您可以通過在其上面寫入`%%cython`來定義 Cython 單元格。像這樣:
```py
%%cython
cdef int a = 0
for i in range(10):
a += i
print(a)
```
請注意,每個單元格將編譯為單獨的擴展模塊。因此,如果您在 Cython 單元格中使用包,則必須在同一單元格中導入此包。在先前的單元格中導入包是不夠的。如果你不遵守,Cython 會告訴你編譯時有“未定義的全局名稱”。
然后將單元格的全局名稱(頂級函數,類,變量和模塊)加載到筆記本的全局命名空間中。所以最后,它的行為就好像你執行了一個 Python 單元格。
下面列出了 Cython 魔術的其他允許參數。您也可以通過在 IPython 或 Jupyter 筆記本中鍵入``%%cython?`來查看它們。
<colgroup><col width="25%"> <col width="75%"></colgroup>
| -a,-annotate | 生成源的彩色 HTML 版本。 |
| -annotate-fullc | 生成源的彩色 HTML 版本,其中包括整個生成的 C / C ++代碼。 |
| - +,-cplus | 輸出 C ++而不是 C 文件。 |
| -f,-force | 強制編譯新模塊,即使以前編譯過源也是如此。 |
| -3 | 選擇 Python 3 語法 |
| -2 | 選擇 Python 2 語法 |
| -c = COMPILE_ARGS,-compile-args = COMPILE_ARGS | 通過 extra_compile_args 傳遞給編譯器的額外標志。 |
| -link-args LINK_ARGS | 通過 extra_link_args 傳遞給鏈接器的額外標志。 |
| -l LIB,-lib LIB | 添加庫以鏈接擴展名(可以多次指定)。 |
| -L dir | 添加庫目錄列表的路徑(可以多次指定)。 |
| - 我包括,包括 INCLUDE | 添加包含目錄列表的路徑(可以多次指定)。 |
| -S,-src | 添加 src 文件列表的路徑(可以多次指定)。 |
| -n NAME, - name NAME | 指定 Cython 模塊的名稱。 |
| -pgo | 在 C 編譯器中啟用配置文件引導優化。編譯單元格兩次并在其間執行以生成運行時配置文件。 |
| -verbose | 打印調試信息,如生成的.c / .cpp 文件位置和調用的精確 gcc / g ++命令。 |
### 編譯器選項
在調用`cythonize()`之前,可以在`setup.py`中設置編譯器選項,如下所示:
```py
from distutils.core import setup
from Cython.Build import cythonize
from Cython.Compiler import Options
Options.docstrings = False
setup(
name = "hello",
ext_modules = cythonize("lib.pyx"),
)
```
以下是可用的選項:
`Cython.Compiler.Options.``docstrings` _= True_
是否在 Python 擴展中包含 docstring。如果為 False,則二進制大小將更小,但任何類或函數的`__doc__`屬性將為空字符串。
`Cython.Compiler.Options.``embed_pos_in_docstring` _= False_
將源代碼位置嵌入到函數和類的文檔字符串中。
`Cython.Compiler.Options.``emit_code_comments` _= True_
將原始源代碼逐行復制到生成的代碼文件中的 C 代碼注釋中,以幫助理解輸出。這也是覆蓋率分析所必需的。
`Cython.Compiler.Options.``generate_cleanup_code` _= False_
在退出時為每個模塊刪除全局變量以進行垃圾回收。 0:無,1 +:實習對象,2 +:cdef 全局,3 +:類型對象主要用于降低 Valgrind 中的噪聲,僅在進程退出時執行(當所有內存都將被回收時)。
`Cython.Compiler.Options.``clear_to_none` _= True_
tp_clear()應該將對象字段設置為 None 而不是將它們清除為 NULL 嗎?
`Cython.Compiler.Options.``annotate` _= False_
生成帶注釋的 HTML 版本的輸入源文件,以進行調試和優化。這與`cythonize()`中的`annotate`參數具有相同的效果。
`Cython.Compiler.Options.``fast_fail` _= False_
這將在第一次發生錯誤時中止編譯,而不是試圖繼續進行并打印更多錯誤消息。
`Cython.Compiler.Options.``warning_errors` _= False_
將所有警告變為錯誤。
`Cython.Compiler.Options.``error_on_unknown_names` _= True_
使未知名稱成為錯誤。 Python 在運行時遇到未知名稱時會引發 NameError,而此選項會使它們成為編譯時錯誤。如果您想要完全兼容 Python,則應禁用此選項以及“cache_builtins”。
`Cython.Compiler.Options.``error_on_uninitialized` _= True_
使未初始化的局部變量引用編譯時錯誤。 Python 在運行時引發 UnboundLocalError,而此選項使它們成為編譯時錯誤。請注意,此選項僅影響“python 對象”類型的變量。
`Cython.Compiler.Options.``convert_range` _= True_
當`i`是 C 整數類型時,這將把`for i in range(...)`形式的語句轉換為`for i from ...`,并且可以確定方向(即步驟的符號)。警告:如果范圍導致 i 的分配溢出,則可能會更改語義。具體來說,如果設置了此選項,則在輸入循環之前將引發錯誤,而如果沒有此選項,則循環將執行,直到遇到溢出值。
`Cython.Compiler.Options.``cache_builtins` _= True_
在模塊初始化時,僅對內置名稱執行一次查找。如果在初始化期間找不到它使用的內置名稱,這將阻止導入模塊。默認為 True。請注意,在 Python 3.x 中構建時,一些遺留的內置函數會自動從 Python 2 名稱重新映射到 Cython 的 Python 3 名稱,這樣即使啟用此選項,它們也不會妨礙它們。
`Cython.Compiler.Options.``gcc_branch_hints` _= True_
生成分支預測提示以加快錯誤處理等。
`Cython.Compiler.Options.``lookup_module_cpdef` _= False_
如果 cpdef 函數為 foo,則啟用此選項以允許寫入`your_module.foo = ...`來覆蓋定義,代價是每次調用時額外的字典查找。如果這是假的,它只生成 Python 包裝器而不進行覆蓋檢查。
`Cython.Compiler.Options.``embed` _= None_
是否嵌入 Python 解釋器,用于制作獨立的可執行文件或從外部庫調用。這將提供一個 C 函數,它初始化解釋器并執行該模塊的主體。有關具體示例,請參見[此演示](https://github.com/cython/cython/tree/master/Demos/embed)。如果為 true,則初始化函數是 C main()函數,但此選項也可以設置為非空字符串以顯式提供函數名稱。默認值為 False。
`Cython.Compiler.Options.``cimport_from_pyx` _= False_
允許從沒有 pxd 文件的 pyx 文件中導入。
`Cython.Compiler.Options.``buffer_max_dims` _= 8_
緩沖區的最大維數 - 設置低于 numpy 中的維數,因為切片按值傳遞并涉及大量復制。
`Cython.Compiler.Options.``closure_freelist_size` _= 8_
要保留在空閑列表中的函數閉包實例數(0:沒有空閑列表)
## 編譯器指令
編譯器指令是影響 Cython 代碼行為的指令。以下是當前支持的指令列表:
`binding` (True / False)
Controls whether free functions behave more like Python’s CFunctions (e.g. [`len()`](https://docs.python.org/3/library/functions.html#len "(in Python v3.7)")) or, when set to True, more like Python’s functions. When enabled, functions will bind to an instance when looked up as a class attribute (hence the name) and will emulate the attributes of Python functions, including introspections like argument names and annotations. Default is False.
`boundscheck` (True / False)
If set to False, Cython is free to assume that indexing operations ([]-operator) in the code will not cause any IndexErrors to be raised. Lists, tuples, and strings are affected only if the index can be determined to be non-negative (or if `wraparound` is False). Conditions which would normally trigger an IndexError may instead cause segfaults or data corruption if this is set to False. Default is True.
`wraparound` (True / False)
In Python, arrays and sequences can be indexed relative to the end. For example, A[-1] indexes the last value of a list. In C, negative indexing is not supported. If set to False, Cython is allowed to neither check for nor correctly handle negative indices, possibly causing segfaults or data corruption. If bounds checks are enabled (the default, see `boundschecks` above), negative indexing will usually raise an `IndexError` for indices that Cython evaluates itself. However, these cases can be difficult to recognise in user code to distinguish them from indexing or slicing that is evaluated by the underlying Python array or sequence object and thus continues to support wrap-around indices. It is therefore safest to apply this option only to code that does not process negative indices at all. Default is True.
`initializedcheck` (True / False)
If set to True, Cython checks that a memoryview is initialized whenever its elements are accessed or assigned to. Setting this to False disables these checks. Default is True.
`nonecheck` (True / False)
If set to False, Cython is free to assume that native field accesses on variables typed as an extension type, or buffer accesses on a buffer variable, never occurs when the variable is set to `None`. Otherwise a check is inserted and the appropriate exception is raised. This is off by default for performance reasons. Default is False.
`overflowcheck` (True / False)
If set to True, raise errors on overflowing C integer arithmetic operations. Incurs a modest runtime penalty, but is much faster than using Python ints. Default is False.
`overflowcheck.fold` (True / False)
If set to True, and overflowcheck is True, check the overflow bit for nested, side-effect-free arithmetic expressions once rather than at every step. Depending on the compiler, architecture, and optimization settings, this may help or hurt performance. A simple suite of benchmarks can be found in `Demos/overflow_perf.pyx`. Default is True.
`embedsignature` (True / False)
If set to True, Cython will embed a textual copy of the call signature in the docstring of all Python visible functions and classes. Tools like IPython and epydoc can thus display the signature, which cannot otherwise be retrieved after compilation. Default is False.
`cdivision` (True / False)
If set to False, Cython will adjust the remainder and quotient operators C types to match those of Python ints (which differ when the operands have opposite signs) and raise a `ZeroDivisionError` when the right operand is 0\. This has up to a 35% speed penalty. If set to True, no checks are performed. See [CEP 516](https://github.com/cython/cython/wiki/enhancements-division). Default is False.
`cdivision_warnings` (True / False)
If set to True, Cython will emit a runtime warning whenever division is performed with negative operands. See [CEP 516](https://github.com/cython/cython/wiki/enhancements-division). Default is False.
`always_allow_keywords` (True / False)
Avoid the `METH_NOARGS` and `METH_O` when constructing functions/methods which take zero or one arguments. Has no effect on special methods and functions with more than one argument. The `METH_NOARGS` and `METH_O` signatures provide faster calling conventions but disallow the use of keywords.
`profile` (True / False)
Write hooks for Python profilers into the compiled C code. Default is False.
`linetrace` (True / False)
Write line tracing hooks for Python profilers or coverage reporting into the compiled C code. This also enables profiling. Default is False. Note that the generated module will not actually use line tracing, unless you additionally pass the C macro definition `CYTHON_TRACE=1` to the C compiler (e.g. using the distutils option `define_macros`). Define `CYTHON_TRACE_NOGIL=1` to also include `nogil` functions and sections.
`infer_types` (True / False)
Infer types of untyped variables in function bodies. Default is None, indicating that only safe (semantically-unchanging) inferences are allowed. In particular, inferring _integral_ types for variables _used in arithmetic expressions_ is considered unsafe (due to possible overflow) and must be explicitly requested.
`language_level` (2/3/3str)
Globally set the Python language level to be used for module compilation. Default is compatibility with Python 2\. To enable Python 3 source code semantics, set this to 3 (or 3str) at the start of a module or pass the “-3” or “–3str” command line options to the compiler. The `3str` option enables Python 3 semantics but does not change the `str` type and unprefixed string literals to `unicode` when the compiled code runs in Python 2.x. Note that cimported files inherit this setting from the module being compiled, unless they explicitly set their own language level. Included source files always inherit this setting.
`c_string_type` (bytes / str / unicode)
Globally set the type of an implicit coercion from char* or std::string.
`c_string_encoding` (ascii, default, utf-8, etc.)
Globally set the encoding to use when implicitly coercing char* or std:string to a unicode object. Coercion from a unicode object to C type is only allowed when set to `ascii` or `default`, the latter being utf-8 in Python 3 and nearly-always ascii in Python 2.
`type_version_tag` (True / False)
Enables the attribute cache for extension types in CPython by setting the type flag `Py_TPFLAGS_HAVE_VERSION_TAG`. Default is True, meaning that the cache is enabled for Cython implemented types. To disable it explicitly in the rare cases where a type needs to juggle with its `tp_dict` internally without paying attention to cache consistency, this option can be set to False.
`unraisable_tracebacks` (True / False)
Whether to print tracebacks when suppressing unraisable exceptions.
`iterable_coroutine` (True / False)
[PEP 492](https://www.python.org/dev/peps/pep-0492/) specifies that async-def coroutines must not be iterable, in order to prevent accidental misuse in non-async contexts. However, this makes it difficult and inefficient to write backwards compatible code that uses async-def coroutines in Cython but needs to interact with async Python code that uses the older yield-from syntax, such as asyncio before Python 3.5\. This directive can be applied in modules or selectively as decorator on an async-def coroutine to make the affected coroutine(s) iterable and thus directly interoperable with yield-from.
### 可配置的優化
`optimize.use_switch` (True / False)
Whether to expand chained if-else statements (including statements like `if x == 1 or x == 2:`) into C switch statements. This can have performance benefits if there are lots of values but cause compiler errors if there are any duplicate values (which may not be detectable at Cython compile time for all C constants). Default is True.
`optimize.unpack_method_calls` (True / False)
Cython can generate code that optimistically checks for Python method objects at call time and unpacks the underlying function to call it directly. This can substantially speed up method calls, especially for builtins, but may also have a slight negative performance impact in some cases where the guess goes completely wrong. Disabling this option can also reduce the code size. Default is True.
### 警告
所有警告指令都采用 True / False 作為打開/關閉警告的選項。
`warn.undeclared` (default False)
Warns about any variables that are implicitly declared without a `cdef` declaration
`warn.unreachable` (default True)
Warns about code paths that are statically determined to be unreachable, e.g. returning twice unconditionally.
`warn.maybe_uninitialized` (default False)
Warns about use of variables that are conditionally uninitialized.
`warn.unused` (default False)
Warns about unused variables and declarations
`warn.unused_arg` (default False)
Warns about unused function arguments
`warn.unused_result` (default False)
Warns about unused assignment to the same name, such as `r = 2; r = 1 + 2`
`warn.multiple_declarators` (default True)
Warns about multiple variables declared on the same line with at least one pointer type. For example `cdef double* a, b` - which, as in C, declares `a` as a pointer, `b` as a value type, but could be mininterpreted as declaring two pointers.
### 如何設置指令
#### 全球
可以通過文件頂部附近的特殊標題注釋設置編譯器指令,如下所示:
```py
# cython: language_level=3, boundscheck=False
```
注釋必須出現在任何代碼之前(但可以出現在其他注釋或空格之后)。
也可以使用-X 開關在命令行上傳遞指令:
```py
$ cython -X boundscheck=True ...
```
在命令行上傳遞的指令將覆蓋在頭注釋中設置的指令。
#### 本地
對于本地塊,您需要使用特殊的內置`cython`模塊:
```py
#!python
cimport cython
```
然后你可以使用指令作為裝飾器或在 with 語句中,如下所示:
```py
#!python
@cython.boundscheck(False) # turn off boundscheck for this function
def f():
...
# turn it temporarily on again for this block
with cython.boundscheck(True):
...
```
警告
這兩種設置指令的方法是**而不是**,它們使用-X 選項覆蓋命令行上的指令。
#### 在`setup.py` 中
通過將關鍵字參數傳遞給`cythonize`,也可以在`setup.py`文件中設置編譯器指令:
```py
from distutils.core import setup
from Cython.Build import cythonize
setup(
name="My hello app",
ext_modules=cythonize('hello.pyx', compiler_directives={'embedsignature': True}),
)
```
這將覆蓋`compiler_directives`字典中指定的默認指令。請注意,如上所述的顯式每文件或本地指令優先于傳遞給`cythonize`的值。
- 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 后端