Курс по Python: https://stepik.org/course/100707
На этом
занятии вы узнаете как создавать и импортировать свои собственные модули. Как мы говорили
на предыдущем уроке, модули представляют собой обычный текстовый файл программы
на 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:
и если теперь
ниже записать:
mymodule.
то, как раз,
увидим наши определения – переменную NAME и имя функции floor. То есть, они
были импортированы в нашу программу и доступны через пространство имен mymodule:
print(mymodule.floor(-5.4))
Или же, можем
воспользоваться другой конструкцией:
from mymodule import floor
и напрямую
вызвать эту функцию:
Но что будет,
если в файле mymodule тоже прописать
импорт, скажем, библиотеки 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 через
конструкцию:
(Еще раз отмечу,
что так делать не рекомендуется. Здесь, я лишь в учебных целях показываю, что
произойдет). В итоге получаем неявное расширение модуля mymodule за счет модуля
math. И все функции из math мы теперь напрямую можем вызывать из mymodule:
a = mymodule.floor(-5.6)
b = mymodule.ceil(-5.6)
print(a, b)
Причем, вот эта
функция floor была
переопределена, поэтому вызывается не библиотечный вариант, а наш. Так вот,
такой импорт ни в коем случае делать не стоит, чтобы не смешивать свои и
стандартные функции в одном месте. Лучше или перечислять, те элементы, что мы
собираемся использовать, например:
from math import pi, ceil
или же
воспользоваться простым импортом:
Давайте теперь
детальнее разберемся, как работает импорт модулей. Первый вопрос, откуда Python «знает», где
искать импортируемые модули? Порядок поиска прописан в специальной коллекции path модуля sys:
import sys
pprint.pprint(sys.path)
Здесь первые
строчки – это каталог с исполняемым модулем ex.py и рабочий
каталог, а далее, идут дополнительные пути поиска, например, для файлов
стандартной библиотеки. Поэтому, если мы переместим файл модуля mymodule из рабочего
каталога, в какую-нибудь вложенную папку, например, с именем folder (создаем и
перемещаем), то при импорте получим ошибку ModuleNotFoundError, так как к этой
папке не прописан путь в коллекции path. Поэтому, нам
дополнительно нужно указать каталог folder, в котором
находится модуль mymodule, следующим образом:
Конечно, в
список path мы можем
добавить путь для поиска модулей:
sys.path.append(r"C:\PythonProjects\example\folder")
и тогда при
импорте по-прежнему достаточно будет прописывать только mymodule. Но это
делается крайне редко, обычно добавляют имена подкаталогов через точку.
Давайте теперь
поменяем местами эти два файла (ex.py и mymodule.py). В этом случае
для импорта достаточно будет также прописать:
так как пути
поиска теперь будут включать и рабочий каталог, где находится mymodule и каталог с
исполняемым файлом.
Вернем файл ex.py в рабочий
каталог. И заметим, что в момент выполнения импорта модуль преобразуется
интерпретатором языка Python сначала в
байт-код, а затем, запускается на исполнение. Это важный момент. Смотрите, если
в mymodule прописать
строчку:
и запустить файл
ex.py на исполнение,
то в консоли увидим результат срабатывания функции print(). Причем она
сработала в момент импорта модуля до вызова функции pprint(). Это
означает, что если в mymodule будет записана программа:
for i in range(5):
print(NAME)
то она будет
выполнена. Так что с этим следует быть аккуратным.
Значит,
получается, что подключаемые модули должны исключительно содержать определения
переменных, функций и других объектов языка Python, но не их
вызовы? Не обязательно! В каждом модуле есть специальная переменная __name__,
которая принимает имя модуля, если они запускается при импорте:
и значение "__main__",
если он запускается как самостоятельная программа (показываем). И это свойство
часто используют для контроля исполнения модуля. Если в нем нужно прописать
программу, выполняемую только при непосредственном запуске модуля, то ее
следует поместить в следующее условие:
if __name__ == "__main__":
print("самостоятельный запуск")
else:
print("запуски при импорте")
Такую проверку
часто можно увидеть в питоновских программах и вы теперь знаете, для чего она
нужна.
Давайте
посмотрим, что произойдет, если в модульном файле сделать импорт проектного:
Чтобы результат
был виден, в проектный файл добавим:
а в модульный:
После запуска
видим, что сначала был выполнен проектный файл, затем, модульный, а потом,
снова проектный. Но почему это выполнение не пошло дальше по цепочке? Дело в
том, что модуль импортируется только один раз. Например, если прописать два
импорта подряд:
import mymodule
import mymodule
то увидим только
одно сообщение. Это, как раз, и доказывает, что модуль был выполнен только один
раз. Если же нам нужно сделать повторный импорт в одной и той же программе, то
для этого следует использовать специальную функцию:
importlib.reload(mymodule)
а перед этим
импортируем специальный модуль
который
доступен, начиная с версии Python 3.4. В качестве аргумента этой
функции передаем ранее импортированный модуль и он будет обновлен без
перезапуска, поэтому второй раз функция print() в нем
выполняться не будет.
Надеюсь, из
этого занятия вам стало понятно, как создавать свои собственные модули, как их
импортировать и как все это работает в деталях. Жду всех вас на следующем
занятии!
Курс по Python: https://stepik.org/course/100707