Импорт собственных модулей

Курс по Python: https://stepik.org/course/100707

Смотреть материал на YouTube | RuTube

На этом занятии вы узнаете как создавать и импортировать свои собственные модули. Как мы говорили на предыдущем уроке, модули представляют собой обычный текстовый файл программы на Python. Поэтому, в текущем рабочем каталоге я создам еще один файл и назову его mymodule.py. (Щелкаем правой кнопкой по вкладке mymodule и выбираем пункт «Split and Move Right»). Запишем в этом модуле следующие строчки:

NAME = 'mymodule'
def floor(x):
    print("функция из mymodule")
    return int(x) if x >= 0 else int(x)1

В результате, в глобальном пространстве имен имеем две переменные: NAME и floor. Все локальные переменные, например, x сюда уже не попадают – только глобальные определения.

Импортируем этот модуль в нашу программу ex.py:

import mymodule

и если теперь ниже записать:

mymodule.

то, как раз, увидим наши определения – переменную NAME и имя функции floor. То есть, они были импортированы в нашу программу и доступны через пространство имен mymodule:

print(mymodule.floor(-5.4))

Или же, можем воспользоваться другой конструкцией:

from mymodule import floor

и напрямую вызвать эту функцию:

print(floor(-5.4))

Но что будет, если в файле mymodule тоже прописать импорт, скажем, библиотеки math, следующим образом:

import math

В этом случае, в модуле mymodule появляется глобальная переменная с именем math. Значит, при импорте уже модуля mymodule (в ex.py):

import mymodule
import pprint

мы должны увидеть это имя:

pprint.pprint(dir(mymodule))

Действительно, в конце списка оно присутствует, а это значит, к модулю math можно обратиться через модуль mymodule:

a = mymodule.math.floor(-5.6)
print(a)

То есть, мы здесь уже имеем иерархию модулей, сначала обращаемся к mymodule, затем к math, а потом к одной из его функций.

Конечно, чтобы не создавать таких цепочек, можно было бы импортировать библиотеку math через конструкцию:

from math import *

(Еще раз отмечу, что так делать не рекомендуется. Здесь, я лишь в учебных целях показываю, что произойдет). В итоге получаем неявное расширение модуля mymodule за счет модуля math. И все функции из math мы теперь напрямую можем вызывать из mymodule:

a = mymodule.floor(-5.6)
b = mymodule.ceil(-5.6)
print(a, b)

Причем, вот эта функция floor была переопределена, поэтому вызывается не библиотечный вариант, а наш. Так вот, такой импорт ни в коем случае делать не стоит, чтобы не смешивать свои и стандартные функции в одном месте. Лучше или перечислять, те элементы, что мы собираемся использовать, например:

from math import pi, ceil

или же воспользоваться простым импортом:

import math

Давайте теперь детальнее разберемся, как работает импорт модулей. Первый вопрос, откуда Python «знает», где искать импортируемые модули? Порядок поиска прописан в специальной коллекции path модуля sys:

import sys
pprint.pprint(sys.path)

Здесь первые строчки – это каталог с исполняемым модулем ex.py и рабочий каталог, а далее, идут дополнительные пути поиска, например, для файлов стандартной библиотеки. Поэтому, если мы переместим файл модуля mymodule из рабочего каталога, в какую-нибудь вложенную папку, например, с именем folder (создаем и перемещаем), то при импорте получим ошибку ModuleNotFoundError, так как к этой папке не прописан путь в коллекции path. Поэтому, нам дополнительно нужно указать каталог folder, в котором находится модуль mymodule, следующим образом:

import folder.mymodule

Конечно, в список path мы можем добавить путь для поиска модулей:

sys.path.append(r"C:\PythonProjects\example\folder")

и тогда при импорте по-прежнему достаточно будет прописывать только mymodule. Но это делается крайне редко, обычно добавляют имена подкаталогов через точку.

Давайте теперь поменяем местами эти два файла (ex.py и mymodule.py). В этом случае для импорта достаточно будет также прописать:

import mymodule

так как пути поиска теперь будут включать и рабочий каталог, где находится mymodule и каталог с исполняемым файлом.

Вернем файл ex.py в рабочий каталог. И заметим, что в момент выполнения импорта модуль преобразуется интерпретатором языка Python сначала в байт-код, а затем, запускается на исполнение. Это важный момент. Смотрите, если в mymodule прописать строчку:

print(NAME)

и запустить файл ex.py на исполнение, то в консоли увидим результат срабатывания функции print(). Причем она сработала в момент импорта модуля до вызова функции pprint(). Это означает, что если в mymodule будет записана программа:

for i in range(5):
    print(NAME)

то она будет выполнена. Так что с этим следует быть аккуратным.

Значит, получается, что подключаемые модули должны исключительно содержать определения переменных, функций и других объектов языка Python, но не их вызовы? Не обязательно! В каждом модуле есть специальная переменная __name__, которая принимает имя модуля, если они запускается при импорте:

print(__name__)

и значение "__main__", если он запускается как самостоятельная программа (показываем). И это свойство часто используют для контроля исполнения модуля. Если в нем нужно прописать программу, выполняемую только при непосредственном запуске модуля, то ее следует поместить в следующее условие:

if __name__ == "__main__":
    print("самостоятельный запуск")
else:
    print("запуски при импорте")

Такую проверку часто можно увидеть в питоновских программах и вы теперь знаете, для чего она нужна.

Давайте посмотрим, что произойдет, если в модульном файле сделать импорт проектного:

import ex

Чтобы результат был виден, в проектный файл добавим:

print("ex.py")

а в модульный:

print("mymodule")

После запуска видим, что сначала был выполнен проектный файл, затем, модульный, а потом, снова проектный. Но почему это выполнение не пошло дальше по цепочке? Дело в том, что модуль импортируется только один раз. Например, если прописать два импорта подряд:

import mymodule
import mymodule

то увидим только одно сообщение. Это, как раз, и доказывает, что модуль был выполнен только один раз. Если же нам нужно сделать повторный импорт в одной и той же программе, то для этого следует использовать специальную функцию:

importlib.reload(mymodule)

а перед этим импортируем специальный модуль

import importlib

который доступен, начиная с версии Python 3.4. В качестве аргумента этой функции передаем ранее импортированный модуль и он будет обновлен без перезапуска, поэтому второй раз функция print() в нем выполняться не будет.

Надеюсь, из этого занятия вам стало понятно, как создавать свои собственные модули, как их импортировать и как все это работает в деталях. Жду всех вас на следующем занятии!

Курс по Python: https://stepik.org/course/100707

Видео по теме