简体   繁体   中英

How to cythonize global __builtin__ objects?

I have a problem "cythonizing" a project written in python.

1. A python class (declared in file ) is instantiated, then "declared global" using setattr(__builtin__...) in file 中声明),然后在文件中使用 setattr(__builtin__...) “声明为全局”
2. A function declared in a module (file ) access this class instance by its global name ("globalclass"), and set some values. )中声明的 function 通过其全局名称(“globalclass”)访问此 class 实例,并设置一些值。

So the question is: How to cythonize a python module referring an object instance by its "global name" definned outside of the module with setattr(__builtin__...)?

I run python 2.7.15 on windows x86, with Cython 0.29.1.

The code provided below works fine when I run pure python:

python main.py


But cythonizing the file gives me an error: referring the global name of the class instance "globalclass".进行 cythonizing 会给我一个错误:的,指的是 class 实例“globalclass”的全局名称。

Here is the file , the definition of the class: ,class 的定义:

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

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

    def printValue(self):
        print self.value


Here is the file : this is the file I want to cythonize, but cython says "globalclass": :这是我想要 cythonize 的文件,但 cython 说的“globalclass”:

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


Here is the file (entry point) where the class is instantiated, and "declared global" using setattr(__builtin__...): (入口点),其中 class 被实例化,并使用 setattr(__builtin__...) “声明为全局”:

import __builtin__
from myclass import Myclass
from module import setValue

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


And here is the file used to cythonize the all:

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)
)

And here is the command I use to cythonize:

python setup.py build_ext --inplace

Here is the error message I get when cythonizing:

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

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

This is an a place where Cython differs from Python (although it isn't documented hugely well). Essentially it assumes that it should be able to resolve all global names at compile-time, while what you're doing affects it at runtime.

Fortunately there's an option to turn this behaviour off . Simply add two lines to setup.py (as shown in the documentation above)

from Cython.Compiler import Options
Options.error_on_unknown_names = False

The cython compiler gets the information about python builtins at runtime.
So modifying 'builtins' before / while compiling will solve the problem without taking further action.
Ie use sitecustomize, usercustomize or some 'yourname'.pth to 'import my_builtin_patching_module' for the compile step. Make sure the import will take your original.py, not the compiled one, otherwise the imported.pyd/.so may be locked, preventing the compiler output.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM