【发布时间】:2019-02-27 08:06:50
【问题描述】:
如果我在ext_modules = cythonize(extensions, language_level=2) 中设置language_level=2,会发生什么变化?难道只是我写的代码应该被解释为Python2?
最终的结果完全一样吗?
【问题讨论】:
-
根据the docs,这不是 cythonize 的直接参数,但可以作为编译器指令传递。
标签: cython
如果我在ext_modules = cythonize(extensions, language_level=2) 中设置language_level=2,会发生什么变化?难道只是我写的代码应该被解释为Python2?
最终的结果完全一样吗?
【问题讨论】:
标签: cython
构建 cython 扩展是一个两步过程:
foo.pyx 文件创建 foo.c 文件。 X 可以是 2.7、3.7 或您喜欢的任何版本。Y 不一定是X,但大多数情况下Y 和X 是相同的。生成的扩展可以与 PythonY 一起使用(它不像 X 那样发挥作用)。
但是,仍然存在一个问题:原始pyx 文件是在哪个 Python 版本中编写的?如果 language_level 未设置,当前 Cython 版本假定 pyx 文件是在版本 2 中编写的(顺便说一句。这不是 IPython-%%cython-magic 的情况,其中文件的版本foo.c 被cythonized)。
这种行为将来会改变,这就是你看到有点恼人的警告的原因,如果你用cython>=0.29构建:
/Main.py:367: FutureWarning: Cython 指令'language_level' 不是 设置,现在使用 2 (Py2)。这将在以后的版本中更改!文件: XXXXXX.pyx
tree = Parsing.p_module(s, pxd, full_module_name)
所以你can explicitly set the language_level,这样你的扩展程序具有相同的行为,独立于它被 cython 化的 Cython 版本。
有关不同行为的一些示例,请参见以下示例。
使用language_level=3:
%%cython -3
print("I'm", "not a tuple")
print(5/4)
结果
I'm not a tuple
1.25
但使用language_level=2:
%%cython -2
print("I'm", "not a tuple")
print(5/4)
结果
("I'm", 'not a tuple') # yet a tuple!
1 # integer division in Python2!
显然以上只是两个例子,还有很多不同之处(例如str & unicode 的东西)。
另一个显着的区别是Python3 disablesimplicit relative imports,这意味着在包内部,我们不再 cimport 使用隐式相对导入
# works with language_level=2
cimport other_local_cymodule
但使用显式相对导入
# works with language_level=3,3str
from . cimport other_local_cymodule
或绝对导入
# works with language_level=3,3str
cimport package.other_local_cymodule
一般来说,我会尽量避免混合使用不同的 language_level 和 Python-interpreter-version,因为这会导致违反直觉的行为。
例如在下面的例子中混合language_level=2和Python3:
%%cython -2
def divide2(int a, int b):
return a/b
def divide3(a, b):
return a/b
>>> divide2(2,3), divide3(2,3)
# (0, 0.66666666)
对于函数divide2,Cython 可以确保“正确”的 Python2-behavior,但如何进行除法取决于 int-object 的行为,它具有正常的 Python3-behavior。
【讨论】: