如何在 Cython 的 setup.py 中指定 Python 3源代码?

我正在尝试在 Cython 做一个“ Hello World”节目,跟随这个教程

我创造了 helloworld.pyx

print("Hello World")

setup.py:

from distutils.core import setup
from Cython.Build import cythonize


setup(
ext_modules = cythonize("helloworld.pyx")
)

如何修改 setup.py 来指定源代码是 Python 3,而不是像教程中那样是 Python 2?如果我从命令行调用“ cython”命令,它接受 -3选项。但是如果我像教程中所示的那样使用 python setup.py build_ext --inplace编译,那么如何指定 Python 3源代码呢?对于 Hello World 程序来说,这可能没有多大关系,但是当我开始在实际项目中使用 Cython 时,这就有关系了。

53103 次浏览

According to official documentation on compilation, the Python language level can be specified using a directive through a special header comment at the top of the file, like this:

#!python
#cython: language_level=3

There doesn't seem to be a way to specify this in setup.py. So if you have many Cython files, you'd have to add the compiler directive to each file. Although the only situation I've met so far that needs this directive is for print() as in your sample, and I've used Cython extensively.

One can pass language_level as an option to the cythonize-function in the setup.py-script:

ext_modules = cythonize(
extensions,
compiler_directives={'language_level' : "3"}   # or "2" or "3str"
)

Another possible syntax is

ext_modules = cythonize(extensions, language_level = "3")

The above might be more convenient than to add

#cython: language_level=3

to every pyx-file in the project, which might become necessary because since Cython 0.29 there is a warning, if the language_level isn't set explicitly:

/Main.py:367: FutureWarning: Cython directive 'language_level' not set, using 2 for now (Py2). This will change in a later release! File: XXXXXX.pyx
tree = Parsing.p_module(s, pxd, full_module_name)


Because language_level is a global setting, the decorator

cimport cython


@cython.language_level("3")
def do_something():
pass

will not even be cythonized.

If you are using a setup.py with Extension, as in this example

from distutils.core import setup
from distutils.extension import Extension
from Cython.Distutils import build_ext


ext_modules = [
Extension("mymodule1",  ["mymodule1.py"]),
Extension("mymodule2",  ["mymodule2.py"]),
]


setup(
name = 'My Program Name',
cmdclass = {'build_ext': build_ext},
ext_modules = ext_modules
)

then you have to add the following snippet to apply the language_level directive (BEFORE the setup(...), thanks codeman48):

for e in ext_modules:
e.cython_directives = {'language_level': "3"} #all are Python-3