Импортировать модуль Python без расширения .py - PullRequest
59 голосов
/ 08 апреля 2010

У меня есть файл с именем foobar (без расширения .py). В том же каталоге у меня есть другой файл Python, который пытается импортировать его:

import foobar

Но это работает, только если я переименую файл в foobar.py. Можно ли импортировать модуль Python, который не имеет расширения .py?

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

Обновление 2: я воспользуюсь решением для ссылок, упомянутым ниже.

Ответы [ 6 ]

40 голосов
/ 08 апреля 2010

Вы можете использовать функцию imp.load_source (из модуля imp) для динамической загрузки модуля по заданному пути файловой системы.

foobar = imp.load_source('foobar', '/path/to/foobar')

Это ТАКОЕ обсуждение также показывает некоторые интересные варианты.

15 голосов
/ 08 апреля 2010

Как уже упоминалось, вы можете использовать imp.load_source, но это сделает ваш код более трудным для чтения.Я бы порекомендовал это только в том случае, если вам нужно импортировать модули, имена или пути которых не известны до времени выполнения.

По какой причине вы не хотите использовать расширение .py?Самым распространенным случаем отказа от использования расширения .py является тот факт, что скрипт python также запускается как исполняемый файл, но вы все равно хотите, чтобы другие модули могли его импортировать.В этом случае может быть полезно перенести функциональность в файл .py с похожим именем, а затем использовать foobar в качестве оболочки.

14 голосов
/ 08 апреля 2010

imp.load_source(module_name, path) должен сделать, или вы можете сделать более подробный imp.load_module(module_name, file_handle, ...) маршрут, если у вас есть дескриптор файла

12 голосов
/ 25 апреля 2017

Вот решение для Python 3.4 +:

from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader 

spec = spec_from_loader("foobar", SourceFileLoader("foobar", "/path/to/foobar"))
foobar = module_from_spec(spec)
spec.loader.exec_module(foobar)

Использование spec_from_loader и явное указание SourceFileLoader заставит механизм загрузить файл в качестве источника, не пытаясь определить тип файла с расширением. Это означает, что вы можете загрузить файл, даже если он не указан в importlib.machinery.SOURCE_SUFFIXES.

Если вы хотите продолжать импортировать файл по имени после первой загрузки, добавьте модуль в sys.modules:

sys.modules['foobar'] = foobar
1 голос
/ 07 июля 2014

Если вы устанавливаете скрипт с менеджером пакетов (deb или аналогичным), другой вариант будет использовать setuptools:

"... нет простого способа сделать так, чтобы имя файла скрипта совпадало с местными соглашениями на платформах Windows и POSIX. Для другого вам часто приходится создавать отдельный файл только для сценария" main ", когда фактический" main " »- это функция где-то в модуле ... setuptools исправляет все эти проблемы, автоматически генерируя для вас сценарии с правильным расширением, а в Windows он даже создает файл .exe ..."

https://pythonhosted.org/setuptools/setuptools.html#automatic-script-creation

0 голосов

importlib вспомогательная функция

Вот удобный, готовый к использованию помощник для замены imp на пример, основанный на том, что было упомянуто по адресу: https://stackoverflow.com/a/43602645/895245

main.py

#!/usr/bin/env python3

import os
import importlib

def import_path(path):
    module_name = os.path.basename(path).replace('-', '_')
    spec = importlib.util.spec_from_loader(
        module_name,
        importlib.machinery.SourceFileLoader(module_name, path)
    )
    module = importlib.util.module_from_spec(spec)
    spec.loader.exec_module(module)
    sys.modules[module_name] = module
    return module

notmain = import_path('not-main')
print(notmain)
print(notmain.x)

не магистральный

x = 1

Пробег:

python3 main.py

Выход:

<module 'not_main' from 'not-main'>
1

Я заменяю - на _, потому что мои импортируемые исполняемые файлы Python без расширения имеют дефисы. Это не обязательно, но дает лучшие имена модулей.

Этот шаблон также упоминается в документах по адресу: https://docs.python.org/3.7/library/importlib.html#importing-a-source-file-directly

Я перешел к нему, потому что после обновления до Python 3.7 import imp печатает:

DeprecationWarning: the imp module is deprecated in favour of importlib; see the module's documentation for alternative uses

и я не знаю, как это отключить.

Протестировано в Python 3.7.3.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...