В крупных Data Science проектах часто приходится сталкиваться с тем, что Python-приложение разрастается и его нужно как-то организовывать. В этой статье мы расскажем вам, как работать с пакетами и модулями Python: разберем запуск модулей, прямые и косвенные обращения, объединение в пакеты, относительные импорты и рекомендации PEP 8 по импорту.
Запуск модулей в командной строке
Python-файлы, или модули, с расширением .py запускаются с командной строки. Файлы, которые находятся в одной папке, могут импортировать переменные, функции и классы друг друга. Рассмотрим пример с двумя файлами, один из которых импортирует функцию другого:
# Файл one.py def foo(s): print(s) foo("python")
# Файл two.py import one one.foo("school")
Строчка import one
не только импортирует файл, но и запускает его, поэтому можно наблюдать двойной результат:
$ python one.py python $ python two.py python school
Для импорта конкретных объектов используют конструкцию from ... import ...
, тогда не потребуется писать вызовы через точку. Ниже показан пример такого использования.
# Файл two.py from one import foo foo("school")
$ python two.py python school
В Python нет главной функции main
В отличие от многих языков программирования, в Python нет функции main()
, которая запускает всю программу. Но, возможно, вам встречалось видеть __name__ == “__main__”
. Дело в том, что Python создает переменную __name__
, которой присваивается имя модуля такое, что:
- если модуль запускается напрямую, то этой переменной будет присвоено
__main__
; - если модуль будет запущен через импорт, то ему будет присвоено само название модуля.
Допустим, у нас также имеется два файла, лежащие в одной папке:
# Файл one.py def foo(s): print(s) def bar(): print(__name__) if __name__ == "__main__": foo("python") bar()
# Файл two.py import one one.foo("school") one.bar()
Запуск файла one.py
присвоит переменной __name__
значение __main__
, тогда этот блок с if
сработает:
$ python one.py python __main__
Запуск файла two.py
, который содержит импорт файла one.py не запустит блок с if, потому что название модуля соответствует one:
$ python two.py school one
В конструкцию __name__ == “__main__”
вставляют код, который может быть запущен только в результате прямого обращения.
Объединяем модули в пакеты
Разбиение разного функционала по файлам — хорошая идея, поскольку в будущем будет удобно к ним обращаться. Именно такую иерархическую структуру имеют библиотеки и фреймворки: мы знаем, что, например, в tf.keras
находится классы для создания архитектуры модели машинного обучения (Machine Learning). Обсудим, что нужно, чтобы организовать свои Python-файлы.
Объединение файлов под одним названием называется пакетом. Чтобы инициализировать такой пакет, достаточно создать пустой файл __init__.py
в папке. Вот так, например, может выглядеть структура пакета:
ml/ __init__.py supervised_learning/ __init__.py decision_tree.py linear_reg.py unsupervised_learning/ __init__.py pca.py k_means.py
Заметим, что сам пакет ml
имеет также два других пакета, так как у каждого из них имеется файл __init__.py
. Теперь импорты могут выглядеть следующим образом:
import ml.supervised_learning.decision_trees from ml.supervised_learning import decision_trees import ml.unsupervised_learning.pca as pca
Эти три строчки примеры абсолютного импорта.
Относительные импорты внутри пакета
Импорт модулей может быть также и относительным. Обращаясь к предыдущему примеру с пакетом ml
, требуется в модуле unsupervised_learning.pca
импортировать k_means
. Это выглядит так:
# внутри ml/unsupervised_learning/pca.py from . import k_means
А чтобы из этого же модуля импортировать supervised_learning.linear_reg
, нужно добавить две точки:
# внутри ml/unsupervised_learning/pca.py from ..supervised_learning import linear_reg
Относительные импорты должны содержать ключевое слово from
. Ниже рассмотрены правильные и неправильные варианты.
# внутри ml/unsupervised_learning/pca.py from . import k_means # ОК (относительный импорт) from ml.unsupervised_learning import k_means # ОК (абсолютный импорт) import k_means # Ошибка import .k_means # Ошибка
С одной стороны, абсолютный импорт делает код более явным: понятно, что и откуда импортируется; с другой стороны, изменение названия пакета приведет к изменению всех частей кода, где он используется.
Наконец, стоит отметить, что относительные импорты работают только для модулей надлежащего пакета, поэтому попытка обратиться к ним со стороны может оказаться неудачей. Но, чтобы обойти эту проблему, нужно указать флаг -m
и запустить в виде модуля. Примеры ниже иллюстрируют правильный и неправильный способ запуска модулей со стороны, которые содержат относительные импорты.
$ python ml/unsupervised_learning/pca.py # Ошибка относительных импортов $ python -m ml.unsupervised_learning.pca # ОК
Рекомендации PEP 8
Здесь мы также приведем примеры импорта согласно PEP 8 — документ с рекомендациями по стилю кодированию на Python.
- Импорт отдельных модулей/пакетов должны осуществляться на разных строчках:
# Правильно import os import sys
# Неправильно import os, sys
Тем не менее, в порядке вещей импортировать объекты из одного модуля/пакета:
# Правильно from subprocess import Popen, PIPE
- Импорты должны находится вверху файла, после комментариев к модулям, после документации и перед глобальными переменными и константами.
- Все “dunders”, то есть все объекты Pythonс двумя нижними подчеркиваниям, должны находиться перед импортами:
"""Это документация к модулю Все dunders находятся перед импортами. """ from __future__ import barry_as_FLUFL __all__ = ['a', 'b', 'c'] __version__ = '0.1' __author__ = 'Cardinal Biggles' import os import sys
- Импорты должны быть сгруппированы по следующему порядку:
- Стандартные Python-библиотеки.
- Связанные сторонние библиотеки.
- Локальные пакеты/модули.
Пустая строка должна быть после каждой группы импортов.
- Рекомендуется использовать абсолютные импорты, так как они более читаемы и отлаживаемы:
import mypkg.sibling from mypkg import sibling from mypkg.sibling import example
Однако, если ваш пакет очень сложно устроен и имеет много вложений, то можно использовать и относительные импорты, чтобы избежать длинного перечисления. С другой стороны, следует задуматься, нужна ли вам такая сложная структура.
- Конструкции
from <module> import *
, которая импортирует все из модуля, нужно избегать, так как есть вероятность, что переменные импортированного модуля и переменные настоящего модуля будут иметь схожие названия.
В следующей статье поговорим о тестировании кода на Python. А как на практике эффективно организовать файлы с вашими Data Science проектами, вы узнаете на наших Python-курсах в лицензированном учебном центре обучения и повышения квалификации IT-специалистов в Москве.