Python предлагает пакет importlib в качестве части стандартной библиотеки модулей. Его задача – обеспечить реализацию оператора импорта Python, а также функции __import__(). В дополнение, importlib дает программисту возможность создать собственный объект (т.н. импортер), который может быть использован для процесса импорта.
Что насчет imp?
Существует еще один модуль, под названием imp, который предоставляет интерфейс механизмам, стоящим за оператором Python import. Этот модуль считается устаревшим для Python 3.4. Предполагается, что importlib следует использовать вместо него.
Этот модуль весьма сложный в использовании, так что мы ограничим наш кругозор, и сосредоточимся на следующих темах:
- Динамический импорт
- Проверка на возможность импорта модуля
- Удобный сторонний модуль под названием import_from_github_com
Динамический импорт
Модуль importlib поддерживает возможность импорта модуля, который был передан строке. Так что давайте создадим несколько простых модулей, с которыми мы сможем работать. Мы выделим каждому модулю одинаковый интерфейс, но дадим им выводить свои названия, чтобы увидеть разницу между ними. Создадим два модуля с разными названиями, вроде foo.py и bar.py, и добавим в них следующий код:
1 2 |
def main(): print(__name__) |
Теперь нам остается только использовать importlib чтобы импортировать их. Давайте посмотрим на следующий код, чтобы сделать именно это. Убедитесь в том, что этот код находится в той же папке, что и созданные ранее два модуля.
1 2 3 4 5 6 7 8 9 10 11 |
import importlib def dynamic_import(module): return importlib.import_module(module) if __name__ == '__main__': module = dynamic_import('foo') module.main() module_two = dynamic_import('bar') module_two.main() |
Здесь мы импортируем модуль importlib и создаем очень простую функцию под названием dynamic_import. Все, что делает эта функция, это вызывает другую функцию importlib — import_module со строкой модуля, который мы ей передали, и возвращает результат этого вызова. Далее, в нашем условном операторе внизу, мы можем вызвать главный метод каждого модуля, который покорно выведет название модуля. Вы, скорее всего, не будете делать это часто в своем коде, но периодически вам может быть нужно импортировать модуль, когда он представлен только в виде строки. Модуль importlib дает возможность сделать именно это.
Проверка импортируемости модуля
Python содержит стиль кодирования под названием EAFP: Easier to ask for forgiveness than permission (легче просить о прощении, чем разрешения). Это значит, что зачастую проще предположить, что что-то существует (к примеру, ключ в словаре), и словить ошибку, если это не так. Ранее мы пытались импортировать модуль, с вероятностью получить ошибку ImportError, если его не существует. Что если нам нужно проверить и увидеть, может ли модуль быть импортированным, чтобы исключить догадки? Вы можете добиться этого с importlib!
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
import importlib.util def check_module(module_name): """ Проверяет, можно ли импортировать модуль без его фактического импорта """ module_spec = importlib.util.find_spec(module_name) if module_spec is None: print('Module: {} not found'.format(module_name)) return None else: print('Module: {} can be imported!'.format(module_name)) return module_spec def import_module_from_spec(module_spec): module = importlib.util.module_from_spec(module_spec) module_spec.loader.exec_module(module) return module if __name__ == '__main__': module_spec = check_module('fake_module') module_spec = check_module('collections') if module_spec: module = import_module_from_spec(module_spec) print(dir(module)) |
Здесь мы импортируем субмодуль из importlib под названием util. В первой части кода check_module содержится настоящая магия, которую мы можем увидеть. В ней мы вызываем функцию find_spec в строке модуля, которая была передана ранее. Сначала мы выполняем передачу фейкового названия, затем мы делаем то же, но с настоящим названием модуля Python. Если вы запустите этот код, вы увидите, что когда вы передаете название неустановленного модуля, функция find_spec вернет None и наш код выведет уведомление о том, что модуль не найден. Если он был найден, тогда мы вернем спецификацию модуля. Мы можем взять эту спецификацию и использовать её для импорта модуля. Или вы можете просто передать строку функции import_module, как мы делали в предыдущем разделе. По этой же причине мы и рассмотрим использование спецификации модуля в качестве альтернативного способа. Взгляните на функцию import_module_from_spec в описанном выше коде. Она принимает спецификацию модуля, которую вернула функция check_module. Далее мы передаем её функции module_from_spec, которая возвращает модуль import. В документации Python рекомендуется запустить модуль после его импорта, это мы и делаем при помощи функции exec_module. Наконец, мы получим модуль и запустим dir Python с ним, чтобы убедиться в том, что данный модуль такой, как мы ожидали.
Импорт из исходного файла
Субмодуль из importlib под названием util может делать один трюк, который я хочу рассмотреть. Вы можете использовать util для импорта модуля, используя только его путь файла и название. Давайте рассмотрим следующий пример, чтобы вы поняли, что к чему:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
import importlib.util def import_source(module_name): module_file_path = module_name.__file__ module_name = module_name.__name__ module_spec = importlib.util.spec_from_file_location( module_name, module_file_path ) module = importlib.util.module_from_spec(module_spec) module_spec.loader.exec_module(module) print(dir(module)) msg = 'The {module_name} module has the following methods: {methods}' print( msg.format(module_name=module_name, methods=dir(module)) ) if __name__ == '__main__': import logging import_source(logging) |
В данном коде мы импортировали модуль logging и передали его нашей функции import_source. После этого, мы берем настоящие имя и путь модуля. Далее мы вызываем передачу этих частей информации в функцию spec_from_file_location модуля util, которая вернет спецификацию модуля. После этого, мы можем использовать те же механизмы importlib, с которыми мы работали в предыдущем разделе статьи для импорта модуля. Теперь, давайте рассмотрим замечательный сторонний модуль Python, который содержит функцию __import__() для импорта пакетов прямо из github!
Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Паблик VK
Одно из самых больших сообществ по Python в социальной сети ВК. Видео уроки и книги для вас!
Импорт из github.com
Этот удобный в использовании пакет под названием import_from_github_com используется для нахождения и загрузки модулей из github. Для установки, вам нужно использовать pip вот так:
1 |
pip install import_from_github_com |
Данный пакет использует несколько инструментов импорта, которые предоставлены в PEP 302, с целью предоставить вам возможность импорта пакета из github. В целом, данный пакет устанавливает другой пакет и добавляет его в локалку. Несмотря на это, вам нужна версия Python начиная с 3.2, а также git и pip для использования данного пакета. После его установки, вы можете попробовать сделать это в вашей оболочке Python:
1 |
from github_com.zzzeek import sqlalchemy |
Выполняется сразу установка модуля из github.
1 2 3 4 5 |
Collecting git+https://github.com/zzzeek/sqlalchemy Cloning https://github.com/zzzeek/sqlalchemy to /tmp/pip-acfv7t06-build Installing collected packages: SQLAlchemy Running setup.py install for SQLAlchemy ... done Successfully installed SQLAlchemy-1.1.0b1.dev0 |
1 |
print(locals()) |
1 2 3 4 |
{'__builtins__': <module 'builtins' (built-in)>, '__spec__': None, '__package__': None, '__doc__': None, '__name__': '__main__', 'sqlalchemy': <module 'sqlalchemy' from '/usr/local/lib/python3.5/site-packages/sqlalchemy/__init__.py'>, '__loader__': <class '_frozen_importlib.BuiltinImporter'>} |
Если вы взглянете на исходный код в import_from_github_com, вы заметите, что он не использует importlib. Вместо этого он использует pip для установки пакета, если он еще не установлен, и затем использует функцию Python __import__(), для непосредственного импорта установленного нового модуля. Это очень креативная часть кода, которой стоит уделить отдельное внимание.
Подведем итоги
С этого момента вы должны прекрасно ориентироваться в том, как использовать importlib и способы импорта в вашем коде. В этой статье достаточно общей информации, и если вам нужно написать свой импортер или загрузчик, то вам стоит углубиться в документацию и исходный код, для дополнительной информации.
Являюсь администратором нескольких порталов по обучению языков программирования Python, Golang и Kotlin. В составе небольшой команды единомышленников, мы занимаемся популяризацией языков программирования на русскоязычную аудиторию. Большая часть статей была адаптирована нами на русский язык и распространяется бесплатно.
E-mail: vasile.buldumac@ati.utm.md
Образование
Universitatea Tehnică a Moldovei (utm.md)
- 2014 — 2018 Технический Университет Молдовы, ИТ-Инженер. Тема дипломной работы «Автоматизация покупки и продажи криптовалюты используя технический анализ»
- 2018 — 2020 Технический Университет Молдовы, Магистр, Магистерская диссертация «Идентификация человека в киберпространстве по фотографии лица»