Как импортировать модуль с указанием полного пути? - PullRequest
933 голосов
/ 16 сентября 2008

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

Ответы [ 26 ]

1066 голосов
/ 16 сентября 2008

Для Python 3.5+ используйте:

import importlib.util
spec = importlib.util.spec_from_file_location("module.name", "/path/to/file.py")
foo = importlib.util.module_from_spec(spec)
spec.loader.exec_module(foo)
foo.MyClass()

Для Python 3.3 и 3.4 используйте:

from importlib.machinery import SourceFileLoader

foo = SourceFileLoader("module.name", "/path/to/file.py").load_module()
foo.MyClass()

(Хотя в Python 3.4 это устарело).

Для Python 2 используйте:

import imp

foo = imp.load_source('module.name', '/path/to/file.py')
foo.MyClass()

Существуют эквивалентные вспомогательные функции для скомпилированных файлов и библиотек Python.

См. Также http://bugs.python.org/issue21436.

361 голосов
/ 24 сентября 2008

Преимущество добавления пути к sys.path (по сравнению с использованием imp) состоит в том, что это упрощает процесс импорта нескольких модулей из одного пакета. Например:

import sys
# the mock-0.3.1 dir contains testcase.py, testutils.py & mock.py
sys.path.append('/foo/bar/mock-0.3.1')

from testcase import TestCase
from testutils import RunTests
from mock import Mock, sentinel, patch
19 голосов
/ 16 сентября 2008

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

Грязно, но работает.

configfile = '~/config.py'

import os
import sys

sys.path.append(os.path.dirname(os.path.expanduser(configfile)))

import config
19 голосов
/ 20 мая 2016

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

from runpy import run_path
settings = run_path("/path/to/file.py")

Этот интерфейс доступен в Python 2.7 и Python 3.2 +

16 голосов
/ 16 сентября 2008

Вы можете использовать

load_source(module_name, path_to_file) 

метод из имп модуля .

15 голосов
/ 17 мая 2018

Если ваш модуль верхнего уровня не является файлом, но упакован как каталог с помощью __init__.py, то принятое решение почти работает, но не совсем. В Python 3.5+ необходим следующий код (обратите внимание на добавленную строку, начинающуюся с 'sys.modules'):

MODULE_PATH = "/path/to/your/module/__init__.py"
MODULE_NAME = "mymodule"
import importlib
import sys
spec = importlib.util.spec_from_file_location(MODULE_NAME, MODULE_PATH)
module = importlib.util.module_from_spec(spec)
sys.modules[spec.name] = module 
spec.loader.exec_module(module)

Без этой строки при выполнении exec_module он пытается привязать относительный импорт в вашем верхнем уровне __init__.py к имени модуля верхнего уровня - в данном случае «mymodule». Но «mymodule» еще не загружен, поэтому вы получите ошибку «SystemError: Родительский модуль« mymodule »не загружен, не может выполнить относительный импорт». Поэтому вам нужно привязать имя, прежде чем загружать его. Причиной этого является фундаментальный инвариант системы относительного импорта: «Инвариантное удержание заключается в том, что если у вас есть sys.modules ['spam'] и sys.modules ['spam.foo'] (как вы сделали бы после вышеупомянутого импорта ), последний должен появляться как атрибут foo предыдущего ", как обсуждено здесь .

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

Я предложил слегка измененную версию @ замечательного ответа Себастьяна Риттау (для Python> 3.4, я думаю), который позволит вам загрузить файл с любым расширением в качестве модуля, используя spec_from_loader вместо spec_from_file_location:

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

spec = spec_from_loader("module.name", SourceFileLoader("module.name", "/path/to/file.py"))
mod = module_from_spec(spec)
spec.loader.exec_module(mod)

Преимущество кодирования пути в явном SourceFileLoader состоит в том, что механизм не будет пытаться определить тип файла по расширению. Это означает, что вы можете загрузить что-то вроде .txt файла, используя этот метод, но вы не можете сделать это с spec_from_file_location без указания загрузчика, потому что .txt отсутствует в importlib.machinery.SOURCE_SUFFIXES.

12 голосов
/ 03 июня 2016

Вот код, который работает во всех версиях Python, начиная с 2.7-3.5 и, возможно, даже в других.

config_file = "/tmp/config.py"
with open(config_file) as f:
    code = compile(f.read(), config_file, 'exec')
    exec(code, globals(), locals())

Я проверял это. Это может быть некрасиво, но пока единственный, который работает во всех версиях.

12 голосов
/ 16 сентября 2008

Вы имеете ввиду загрузку или импорт?

Вы можете манипулировать списком sys.path, указывать путь к вашему модулю, а затем импортировать ваш модуль. Например, заданный модуль по адресу:

/foo/bar.py

Вы можете сделать:

import sys
sys.path[0:0] = ['/foo'] # puts the /foo directory at the start of your path
import bar
12 голосов
/ 15 ноября 2018

Чтобы импортировать ваш модуль, вам нужно добавить его каталог в переменную окружения, временно или постоянно.

Временно

import sys
sys.path.append("/path/to/my/modules/")
import my_module

Постоянно

Добавление следующей строки в файл .bashrc (в linux) и исключение source ~/.bashrc в терминале:

export PYTHONPATH="${PYTHONPATH}:/path/to/my/modules/"

Кредит / Источник: saarrrr , другой вопрос обмена стека

...