В этом разделе показаны практические приемы работы с пакетом importlib
.
importlib.import_module()
Чтобы программно импортировать модуль, используйте importlib.import_module()
.
import importlib itertools = importlib.import_module('itertools')
Если вам нужно выяснить, можно ли импортировать модуль без фактического импорта, вам следует использовать importlib.util.find_spec ()
.
import importlib.util import sys # чисто для иллюстрации name = 'itertools' if name in sys.modules: print(f"{name!r} already in sys.modules") elif (spec := importlib.util.find_spec(name)) is not None: # Если надо выполнить фактический импорт ... module = importlib.util.module_from_spec(spec) sys.modules[name] = module spec.loader.exec_module(module) print(f"{name!r} has been imported") else: print(f"can't find the {name!r} module")
Чтобы импортировать исходный файл Python напрямую, используйте следующий рецепт (только Python 3.5 и новее):
import importlib.util import sys # чисто для иллюстрации import tokenize file_path = tokenize.__file__ module_name = tokenize.__name__ spec = importlib.util.spec_from_file_location(module_name, file_path) module = importlib.util.module_from_spec(spec) sys.modules[module_name] = module spec.loader.exec_module(module)
Для глубокой настройки импорта обычно требуется реализовать импортер. Это означает, что нужно управлять как поиском, так и загрузчиком. Для поиска есть два варианта на выбор в зависимости от ваших потребностей: поиск мета-пути или поиск пути. Первый - это то, что вы бы поместили в sys.meta_path
, а второй - то, что вы создаете, используя хук записи пути к sys.path_hooks
, который работает с записями sys.path
.
В этом примере показано, как зарегистрировать собственных импортеров, чтобы их использовал импорт:
import importlib.machinery import sys # чисто для иллюстрации SpamMetaPathFinder = importlib.machinery.PathFinder SpamPathEntryFinder = importlib.machinery.FileFinder loader_details = (importlib.machinery.SourceFileLoader, importlib.machinery.SOURCE_SUFFIXES) # Настройка мета пути поиска. # необходимо поместить искатель в нужное # место в списке с точки зрения приоритета. sys.meta_path.append(SpamMetaPathFinder) # Настройка поиска пути. # Нужно убедиться в том, что путь перехвачен в # правильном месте в списке, с точки зрения приоритета. sys.path_hooks.append(SpamPathEntryFinder.path_hook(loader_details))
importlib.import_module()
:Ниже представлена приблизительная реализация функции importlib.import_module()
. Этот код помогает проиллюстрировать различные API, которые предоставляет пакет importlib
.
import importlib.util import sys def import_module(name, package=None): """An approximate implementation of import.""" absolute_name = importlib.util.resolve_name(name, package) try: return sys.modules[absolute_name] except KeyError: pass path = None if '.' in absolute_name: parent_name, _, child_name = absolute_name.rpartition('.') parent_module = import_module(parent_name) path = parent_module.__spec__.submodule_search_locations for finder in sys.meta_path: spec = finder.find_spec(absolute_name, path) if spec is not None: break else: msg = f'No module named {absolute_name!r}' raise ModuleNotFoundError(msg, name=absolute_name) module = importlib.util.module_from_spec(spec) sys.modules[absolute_name] = module spec.loader.exec_module(module) if path is not None: setattr(parent_module, child_name, module) return module