如何 cythonize 全局 __builtin__ 对象?

How to cythonize global __builtin__ objects?

我有一个问题"cythonizing"一个用python写的项目。

1.实例化一个pythonclass(在文件myclass.py中声明),然后"declared global"使用setattr(__builtin__ ...) 在文件 main.py
中 2. 在模块(文件module.py)中声明的函数通过其全局名称("globalclass")访问此class实例,并设置一些值.

所以问题是:如何通过 setattr(__builtin__...) 在模块外部定义的 "global name" 来引用对象实例的 python 模块?

I 运行 python 2.7.15 on windows x86,Cython 0.29.1.

当我 运行 pure python:

时,下面提供的代码工作正常
python main.py


但是 cythonizing 文件 module.py 给我一个错误: undeclared name not builtin reference the global name of the class instance "globalclass".

这里是文件myclass.pyx,class的定义:

class Myclass:
    def __init__(self):
        self.value = ''

    def setValue(self,text):
        self.value = text

    def printValue(self):
        print self.value


这是文件 module.pyx:这是我要用 cython 处理的文件,但是 cython 说 undeclared name not builtin "globalclass":

def setValue():
    globalclass.setValue('test from module.py')


这是文件 main.py(入口点),其中 class 被实例化,"declared global" 使用 setattr(__builtin__... ):

import __builtin__
from myclass import Myclass
from module import setValue

if __name__ == '__main__':
    myclass = Myclass()
    setattr(__builtin__, 'globalclass', myclass)
    setValue()
    globalclass.printValue()


这里是用于 cythonize 的文件 setup.py:

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

cyextensions = [
    Extension(name='myclass', sources=['myclass.pyx']),
    Extension(name='module', sources=['module.pyx']),
    ]

setup(name='test',
      version = '0.0.1',
      description = 'test',
      packages = ['test'],
      ext_modules = cythonize(cyextensions)
)

这是我用来进行 cythonize 的命令:

python setup.py build_ext --inplace

这是我在 cythonizing 时收到的错误消息:

Error compiling Cython file:
------------------------------------------------------------
...
def setValue():
        globalclass.setValue('test from module.py')^
------------------------------------------------------------

module.pyx:2:1: undeclared name not builtin: globalclass

这是 Cython 与 Python 不同的地方(尽管没有很好地记录)。本质上它假设它应该能够在编译时解析所有全局名称,而你正在做的事情会在运行时影响它。

Fortunately there's an option to turn this behaviour off。只需在 setup.py 中添加两行(如上面的文档所示)

from Cython.Compiler import Options
Options.error_on_unknown_names = False

cython 编译器在运行时获取有关 python 内置函数的信息。
所以在编译之前/编译时修改'builtins'将解决问题而不需要采取进一步的行动。
即使用 sitecustomize、usercustomize 或一些 'yourname'.pth 来 'import my_builtin_patching_module' 用于编译步骤。 确保导入将采用您的原始 .py,而不是编译后的文件, 否则导入的 .pyd/.so 可能会被锁定,从而阻止编译器输出。