2013-09-25 2 views
26

Как импортировать произвольный исходный файл python (чье имя файла может содержать любые символы и не всегда заканчивается .py) в Python 3.3+?Импортировать произвольный исходный файл python. (Python 3.3+)

Я использовал imp.load_module следующим образом:

>>> import imp 
>>> path = '/tmp/a-b.txt' 
>>> with open(path, 'U') as f: 
...  mod = imp.load_module('a_b', f, path, ('.py', 'U', imp.PY_SOURCE)) 
... 
>>> mod 
<module 'a_b' from '/tmp/a-b.txt'> 

Он по-прежнему работает в Python 3.3, но согласно imp.load_module документации, она устарела:

Устаревший начиная с версии 3.3: Ненужные грузчиками должен использоваться для загрузочных модулей, а find_module() устарел.

и imp модуль документации рекомендуется использовать importlib:

Примечание Новые программы должны использовать importlib вместо этого модуля.

Каков правильный способ загрузить произвольный исходный файл python в Python 3.3+ без использования устаревшей функции imp.load_module?

+2

Могу ли я спросить, почему вы это делаете? Я поддерживаю importlib, и я пытаюсь получить ответы от людей о том, почему они используют 'imp.load_module()' над прямым оператором импорта. Ожидаете ли вы позже импортировать модуль по имени (например, «import a_b»)? Вам все равно, что какие-либо пользовательские импортеры не будут использоваться в этом подходе? Ожидаете ли вы, что модуль будет полнофункциональным (например, определите '__name__' и' __loader__')? –

+1

@BrettCannon, сторонняя программа регулярно (один раз в час) модифицирует текстовый файл, содержащий инструкции python (в основном, строки 'THIS = 'blah''). Имя файла не заканчивается на '.py'. Моя программа прочитала этот файл. – falsetru

+1

@BrettCannon, мне неизвестны пользовательские импортеры. Мне все равно, что модуль будет полнофункциональным. – falsetru

ответ

36

Найдено результатов: importlib test code.

Использование importlib.machinery.SourceFileLoader:

>>> import importlib.machinery 
>>> loader = importlib.machinery.SourceFileLoader('a_b', '/tmp/a-b.txt') 
>>> mod = loader.load_module() 
>>> mod 
<module 'a_b' from '/tmp/a-b.txt'> 

ПРИМЕЧАНИЕ: работает только в Python 3.3+.

UPDATELoader.load_module устарел с Python 3.4. Используйте Loader.exec_module вместо:

>>> import types 
>>> import importlib.machinery 
>>> loader = importlib.machinery.SourceFileLoader('a_b', '/tmp/a-b.txt') 
>>> mod = types.ModuleType(loader.name) 
>>> loader.exec_module(mod) 
>>> mod 
<module 'a_b'> 

>>> import importlib.machinery 
>>> import importlib.util 
>>> loader = importlib.machinery.SourceFileLoader('a_b', '/tmp/a-b.txt') 
>>> spec = importlib.util.spec_from_loader(loader.name, loader) 
>>> mod = importlib.util.module_from_spec(spec) 
>>> loader.exec_module(mod) 
>>> mod 
<module 'a_b' from '/tmp/a-b.txt'> 
+15

Downvoter: Как я могу улучшить ответ? Если у вас есть лучший способ выполнить то, что я хочу, пожалуйста, дайте мне знать. – falsetru

+2

Существует предупреждение, которое 'load_module' игнорирует через' warnings.catch_warnings'. Если вы вместо этого используете 'mod = imp.load_source ('a_b', '/tmp/a-b.txt')', он вызывает следующее предупреждение (используйте '-Wall'):' DeprecationWarning: imp.load_source() устарела; используйте importlib.machinery.SourceFileLoader (имя, путь) .load_module() вместо '. – eryksun

+1

@eryksun, Ты прав. Спасибо за комментарий. BTW, Python 3.4 (rc1) не отображает альтернативное использование, в отличие от Python 3.3.x. – falsetru

4

Сокращенный вариант решения @falsetrue «s:

>>> import importlib.util 
>>> spec = importlib.util.spec_from_file_location('a_b', '/tmp/a-b.py') 
>>> mod = importlib.util.module_from_spec(spec) 
>>> spec.loader.exec_module(mod) 
>>> mod 
<module 'a_b' from '/tmp/a-b.txt'> 

я тестировал его с Python 3.5 и 3.6.

Согласно комментариям, он не работает с произвольными расширениями файлов.

+1

'importlib.util.spec_from_file_location (..)' возвращает 'None' для меня; вызывая исключение для следующего вызова 'importlib.util.module_from_spec (..)'. (См. Https://i.imgur.com/ZjyFhif.png) – falsetru

+0

'importlib.util.spec_from_file_location' работает для известных расширений имен файлов (' .py', '.so', ..), но не для других ('.txt' ...) – falsetru

+0

О, я использую его только с файлами Python, но изменил свой пример, чтобы он выглядел как выше, и не тестировал его ... Я его обновил. –

Смежные вопросы