Как переопределить импорт Python? - PullRequest
30 голосов
/ 10 июня 2010

Я работаю над pypreprocessor , который является препроцессором, который принимает директивы в стиле c, и я смог заставить его работать как традиционный препроцессор (он самопотребляет и выполняет постобработанный код на the-fly) за исключением того, что он нарушает импорт библиотеки.

Проблема: препроцессор запускает файл, обрабатывает его, выводит во временный файл и выполняет exec () временный файл. Импортируемые библиотеки необходимо обрабатывать немного по-другому, поскольку они не выполняются, а загружаются и становятся доступными для модуля вызывающей стороны.

Что мне нужно сделать, это: прервать импорт (поскольку препроцессор выполняется в середине импорта), загрузить постобработанный код как tempModule и заменить исходный импорт на tempModule, чтобы обмануть вызывая скрипт с импортом, полагая, что tempModule является исходным модулем.

Я искал везде и до сих пор, и у меня нет решения.

Этот вопрос переполнения стека наиболее близок к тому, что я видел до сих пор: Переопределить пространство имен в Python

Вот что у меня есть.

# Remove the bytecode file created by the first import
os.remove(moduleName + '.pyc')

# Remove the first import
del sys.modules[moduleName]

# Import the postprocessed module
tmpModule = __import__(tmpModuleName)

# Set first module's reference to point to the preprocessed module
sys.modules[moduleName] = tmpModule

moduleName - это имя исходного модуля, а tmpModuleName - имя файла кода после обработки.

Странно то, что это решение по-прежнему работает совершенно нормально, как будто первый модуль завершен нормально загруженным; если вы не удалите последнюю строку, вы получите ошибку «модуль не найден».

Надеюсь, кто-то в Stack Overflow знает об импорте намного больше, чем я, потому что этот меня озадачил.

Примечание: я только награду решение, или, если это невозможно в Python; лучшее, самое подробное объяснение, почему это не невозможно.

Обновление: для всех, кто заинтересован, вот рабочий код.

if imp.lock_held() is True:
    del sys.modules[moduleName]
    sys.modules[tmpModuleName] = __import__(tmpModuleName)
    sys.modules[moduleName] = __import__(tmpModuleName)

Часть 'imp.lock_held' определяет, загружается ли модуль как библиотека. Следующие строки делают все остальное.

Ответы [ 4 ]

35 голосов
/ 19 июня 2010

Это отвечает на ваш вопрос?Второй импорт делает свое дело.

Mod_1.py

def test_function():
    print "Test Function -- Mod 1"

Mod_2.py

def test_function():
    print "Test Function -- Mod 2"

Test.py

#!/usr/bin/python

import sys

import Mod_1

Mod_1.test_function()

del sys.modules['Mod_1']

sys.modules['Mod_1'] = __import__('Mod_2')

import Mod_1

Mod_1.test_function()
12 голосов
/ 19 июня 2010

Чтобы определить другое поведение при импорте или полностью подорвать процесс импорта, вам нужно написать хуки импорта.См. PEP 302 .

Например,

import sys

class MyImporter(object):

    def find_module(self, module_name, package_path):
        # Return a loader
        return self

    def load_module(self, module_name):
        # Return a module
        return self

sys.meta_path.append(MyImporter())

import now_you_can_import_any_name
print now_you_can_import_any_name

Он выводит:

<__main__.MyImporter object at 0x009F85F0>

Таким образом, в основном он возвращает новый модуль (быть любым объектом), в этом случае сам.Вы можете использовать его, чтобы изменить поведение импорта, возвращая processe_xxx при импорте xxx.

IMO: Python не нуждается в препроцессоре.Все, что вы делаете, может быть выполнено в самом Python благодаря его очень динамичной природе, например, в случае с примером отладки, что не так с наличием вверху файла

debug = 1

и позже

if debug:
   print "wow"

?

1 голос
/ 19 июня 2010

В Python 2 есть модуль imputil, который, кажется, обеспечивает требуемую функциональность, но был удален в Python 3. Он не очень хорошо документирован, но содержит пример раздела, который показываеткак вы можете заменить стандартные функции импорта.

Для Python 3 есть модуль importlib (представлен в Python 3.1), который содержит функции и классы для изменения функциональности импорта во всех видах.способов.Он должен подходить для подключения вашего препроцессора в систему импорта.

0 голосов
/ 10 июня 2010

Очень странный подход - эмулировать низкоуровневый язык высокоуровневым. Если первый простой способ не работает, может быть, это неправильная цель?

Кстати, препроцессор C просто работает с текстовыми файлами и набором переменных препроцессора, а не загружаемых / выгружаемых модулей высокого уровня.

...