Как cythonize глобальные объекты __builtin__?

У меня возникла проблема с «китонизацией» проекта, написанного на python.

1. Создается экземпляр класса python (объявленный в файле myclass.py), а затем «объявляется глобальным» с помощью setattr(__builtin__...) в файле main.py
2. Функция, объявленная в модуле (файл module.py), обращается к этому экземпляру класса по его глобальное имя ("globalclass") и установите некоторые значения.

Итак, вопрос: как cythonize модуль python, ссылающийся на экземпляр объекта по его «глобальному имени», определенному вне модуля с помощью setattr(__builtin__...) ?

Я запускаю Python 2.7.15 на Windows x86 с Cython 0.29.1.

Приведенный ниже код отлично работает, когда я запускаю чистый Python:

python main.py


Но цитирование файла module.py дает мне ошибку: необъявленное имя, не встроенное, ссылающееся на глобальное имя экземпляра класса "globalclass".

Вот файл myclass.pyx, определение класса:

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

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

    def printValue(self):
        print self.value


Вот файл module.pyx: это файл, который я хочу cythonize, но cython говорит необъявленное имя не встроено "globalclass":

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


Вот файл main.py (точка входа), в котором класс создается и "объявлен глобальным" с помощью setattr(__builtin__...):

import __builtin__
from myclass import Myclass
from module import setValue

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


А вот файл 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)
)

А вот команда, которую я использую для цитонизации:

python setup.py build_ext --inplace

Вот сообщение об ошибке, которое я получаю при цитировании:

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

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

person jujules83    schedule 04.10.2019    source источник


Ответы (2)


Это место, где Cython отличается от Python (хотя это не очень хорошо документировано). По сути, он предполагает, что он должен иметь возможность разрешать все глобальные имена во время компиляции, в то время как то, что вы делаете, влияет на это во время выполнения.

К счастью, есть возможность изменить это поведение выкл.. Просто добавьте две строки в setup.py (как показано в документации выше)

from Cython.Compiler import Options
Options.error_on_unknown_names = False
person DavidW    schedule 04.10.2019

Компилятор cython получает информацию о встроенных модулях python во время выполнения.
Таким образом, изменение «встроенных модулей» до/во время компиляции решит проблему без дополнительных действий.
Т.е. используйте sitecustomize, usercustomize или какое-либо «ваше имя».pth для «импорта my_builtin_patching_module» для этапа компиляции. Убедитесь, что при импорте будет использоваться исходный .py, а не скомпилированный, иначе импортированные .pyd/.so могут быть заблокированы, что помешает компилятору вывести данные.

person houbit    schedule 30.05.2020