ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 05.12.2023
Просмотров: 846
Скачиваний: 3
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
СОДЕРЖАНИЕ
ГЛ А В А
12
Модули и пакеты
Модулем в языке Python называется любой файл с программным кодом. Каждый модуль может импортировать другой модуль, получая таким образом доступ к атрибутам (пере- менным, функциям и классам), объявленным внутри импортированного модуля. Следует заметить, что импортируемый модуль может содержать программу не только на Python — можно импортировать скомпилированный модуль, написанный на языке C.
Все программы, которые мы запускали ранее, были расположены в модуле с названием "__main__"
. Получить имя модуля позволяет предопределенный атрибут
__name__
. Для за- пускаемого модуля он содержит значение "__main__"
, а для импортируемого модуля — его имя. Выведем название модуля: print(__name__) # Выведет: __main__
Проверить, является модуль главной программой или импортированным модулем, позволя- ет код, приведенный в листинге 12.1.
Листинг 12.1. Проверка способа запуска модуля if __name__ == "__main__": print("Это главная программа") else: print("Импортированный модуль")
12.1. Инструкция import
Импортировать модуль позволяет инструкция import
. Мы уже не раз обращались к этой инструкции для подключения встроенных модулей. Например, подключали модуль time для получения текущей даты с помощью функции strftime()
: import time # Импортируем модуль time print(time.strftime("%d.%m.%Y")) # Выводим текущую дату
Инструкция import имеет следующий формат: import <Название модуля 1> [as <Псевдоним 1>][, ...,
<Название модуля N> [as <Псевдоним N>]]
После ключевого слова import указывается название модуля. Обратите внимание на то, что название не должно содержать расширения и пути к файлу. При именовании модулей необ-
232
Часть I. Основы языка Python ходимо учитывать, что операция импорта создает одноименный идентификатор, — это означает, что название модуля должно полностью соответствовать правилам именования переменных. Можно создать модуль с именем, начинающимся с цифры, но импортировать такой модуль нельзя. Кроме того, следует избегать совпадения имен модулей с ключевыми словами, встроенными идентификаторами и названиями модулей, входящих в стандартную библиотеку.
За один раз можно импортировать сразу несколько модулей, записав их через запятую. Для примера подключим модули time и math
(листинг 12.2).
Листинг 12.2. Подключение нескольких модулей сразу import time, math # Импортируем несколько модулей сразу print(time.strftime("%d.%m.%Y")) # Текущая дата print(math.pi) # Число pi
После импортирования модуля его название становится идентификатором, через который можно получить доступ к атрибутам, определенным внутри модуля. Доступ к атрибутам модуля осуществляется с помощью точечной нотации. Например, обратиться к константе pi
, расположенной внутри модуля math
, можно так: math.pi
Функция getattr()
позволяет получить значение атрибута модуля по его названию, задан- ному в виде строки. С помощью этой функции можно сформировать название атрибута динамически во время выполнения программы. Формат функции: getattr(<Объект модуля>, <Атрибут>[, <Значение по умолчанию>])
Если указанный атрибут не найден, возбуждается исключение
AttributeError
. Чтобы избе- жать вывода сообщения об ошибке, в третьем параметре можно указать значение, которое будет возвращаться, если атрибут не существует. Пример использования функции приведен в листинге 12.3.
Листинг 12.3. Пример использования функции getattr() import math print(getattr(math, "pi")) # Число pi print(getattr(math, "x", 50)) # Число 50, т. к. x не существует
Проверить существование атрибута позволяет функция hasattr(<Объект>, <Название атри- бута>)
. Если атрибут существует, функция возвращает значение
True
. Напишем функцию проверки существования атрибута в модуле math
(листинг 12.4).
Листинг 12.4. Проверка существования атрибута import math def hasattr_math(attr): if hasattr(math, attr): return "Атрибут существует" else: return "Атрибут не существует" print(hasattr_math("pi")) # Атрибут существует print(hasattr_math("x")) # Атрибут не существует
Глава 12. Модули и пакеты
233
Если название модуля слишком длинное и его неудобно указывать каждый раз для доступа к атрибутам модуля, то можно создать псевдоним. Псевдоним задается после ключевого слова as
. Создадим псевдоним для модуля math
(листинг 12.5).
Листинг 12.5. Использование псевдонимов import math as m # Создание псевдонима print(m.pi) # Число pi
Теперь доступ к атрибутам модуля math может осуществляться только с помощью иденти- фикатора m
. Идентификатор math в этом случае использовать уже нельзя.
Все содержимое импортированного модуля доступно только через название или псевдоним, указанный в инструкции import
. Это означает, что любая глобальная переменная на самом деле является глобальной переменной модуля. По этой причине модули часто используются как пространства имен. Для примера создадим модуль под названием tests.py
, в котором определим переменную x
(листинг 12.6).
Листинг 12.6. Содержимое модуля tests.py
# -*- coding: utf-8 -*- x = 50
В основной программе также определим переменную x
, но с другим значением. Затем под- ключим файл tests.py и выведем значения переменных (листинг 12.7).
Листинг 12.7. Содержимое основной программы
# -*- coding: utf-8 -*- import tests # Подключаем файл tests.py x = 22 print(tests.x) # Значение переменной x внутри модуля print(x) # Значение переменной x в основной программе input()
Оба файла размещаем в одной папке, а затем запускаем файл с основной программой с по- мощью двойного щелчка на значке файла. Как видно из результата, никакого конфликта имен нет, поскольку одноименные переменные расположены в разных пространствах имен.
Как говорилось еще в главе 1, перед собственно выполнением каждый модуль Python ком- пилируется, преобразуясь в особое внутреннее представление (байт-код), — это делается для ускорения выполнения кода. Файлы с откомпилированным кодом хранятся в папке
__pycache__
, автоматически создающейся в папке, где находится сам файл с исходным, неоткомпилированным кодом модуля, и имеют имена вида
<имя файла с исходным ко- дом>.cpython-<первые две цифры номера версии Python>.pyc
. Так, при запуске на исполне- ние нашего файла tests.py откомпилированный код будет сохранен в файле tests.cpython-
36.pyc
Следует заметить, что для импортирования модуля достаточно иметь только файл с отком- пилированным кодом, файл с исходным кодом в этом случае не нужен. Для примера пере- именуйте файл tests.py
(например, в tests1.py
), скопируйте файл tests.cpython-36.pyc из пап- ки
__pycache__
в папку с основной программой и переименуйте его в tests.pyc
, а затем за-
234
Часть I. Основы языка Python пустите основную программу. Программа будет нормально выполняться. Таким образом, чтобы скрыть исходный код модулей, можно поставлять клиентам программу только с фай- лами, имеющими расширение pyc
Существует еще одно обстоятельство, на которое следует обратить внимание. Импортиро- вание модуля выполняется только при первом вызове инструкции import
(или from
, речь о которой пойдет позже). При каждом вызове инструкции import проверяется наличие объекта модуля в словаре modules из модуля sys
. Если ссылка на модуль находится в этом словаре, то модуль повторно импортироваться не будет. Для примера выведем ключи сло- варя modules
, предварительно отсортировав их (листинг 12.8).
Листинг 12.8. Вывод ключей словаря modules
# -*- coding: utf-8 -*- import tests, sys # Подключаем модули tests и sys print(sorted(sys.modules.keys())) input()
Инструкция import требует явного указания объекта модуля. Так, нельзя передать название модуля в виде строки. Чтобы подключить модуль, название которого формируется про- граммно, следует воспользоваться функцией
__import__()
. Для примера подключим модуль tests py с помощью функции
__import__()
(листинг 12.9).
Листинг 12.9. Использование функции __import__()
# -*- coding: utf-8 -*- s = "test" + "s" # Динамическое создание названия модуля m = __import__(s) # Подключение модуля tests print(m.x) # Вывод значения атрибута x input()
Получить список всех идентификаторов внутри модуля позволяет функция dir()
. Кроме того, можно воспользоваться словарем
__dict__
, который содержит все идентификаторы и их значения (листинг 12.10).
Листинг 12.10. Вывод списка всех идентификаторов
# -*- coding: utf-8 -*- import tests print(dir(tests)) print(sorted(tests.__dict__.keys())) input()
12.2. Инструкция from
Для импортирования только определенных идентификаторов из модуля можно воспользо- ваться инструкцией from
. Ее формат таков: from <Название модуля> import <Идентификатор 1> [as <Псевдоним 1>]
[, ..., <Идентификатор N> [as <Псевдоним N>]]
Глава 12. Модули и пакеты
235 from <Название модуля> import (<Идентификатор 1> [as <Псевдоним 1>],
[..., <Идентификатор N> [as <Псевдоним N>]]) from <Название модуля> import *
Первые два варианта позволяют импортировать модуль и сделать доступными только ука- занные идентификаторы. Для длинных имен можно назначить псевдонимы, указав их после ключевого слова as
. В качестве примера сделаем доступными константу pi и функцию floor()
из модуля math
, а для названия функции создадим псевдоним (листинг 12.11).
Листинг 12.11. Инструкция from
# -*- coding: utf-8 -*- from math import pi, floor as f print(pi) # Вывод числа pi
# Вызываем функцию floor() через идентификатор f print(f(5.49)) # Выведет: 5 input()
Идентификаторы можно разместить на нескольких строках, указав их названия через запя- тую внутри круглых скобок: from math import (pi, floor, sin, cos)
Третий вариант формата инструкции from позволяет импортировать из модуля все иденти- фикаторы. Для примера импортируем все идентификаторы из модуля math
(листинг 12.12).
Листинг 12.12. Импорт всех идентификаторов из модуля
# -*- coding: utf-8 -*- from math import * # Импортируем все идентификаторы из модуля math print(pi) # Вывод числа pi print(floor(5.49)) # Вызываем функцию floor() input()
Следует заметить, что идентификаторы, названия которых начинаются с символа подчерки- вания, импортированы не будут. Кроме того, необходимо учитывать, что импортирование всех идентификаторов из модуля может нарушить пространство имен главной программы, т. к. идентификаторы, имеющие одинаковые имена, будут перезаписаны.
Создадим два модуля и подключим их с помощью инструкций from и import
. Содержимое файла module1.py приведено в листинге 12.13.
Листинг 12.13. Содержимое файла module1.py
# -*- coding: utf-8 -*- s = "Значение из модуля module1"
Содержимое файла module2.py приведено в листинге 12.14.
Листинг 12.14. Содержимое файла module2.py
# -*- coding: utf-8 -*- s = "Значение из модуля module2"
236
Часть I. Основы языка Python
Исходный код основной программы приведен в листинге 12.15.
Листинг 12.15. Код основной программы
# -*- coding: utf-8 -*- from module1 import * from module2 import * import module1, module2 print(s) # Выведет: "Значение из модуля module2" print(module1.s) # Выведет: "Значение из модуля module1" print(module2.s) # Выведет: "Значение из модуля module2" input()
Итак, в обоих модулях определена переменная с именем s
. Размещаем все файлы в одной папке, а затем запускаем основную программу с помощью двойного щелчка на значке фай- ла. При импортировании всех идентификаторов значением переменной s
станет значение из модуля, который был импортирован последним, — в нашем случае это значение из модуля module2.py
. Получить доступ к обеим переменным можно только при использовании инст- рукции import
. Благодаря точечной нотации пространство имен не нарушается.
В атрибуте
__all__
можно указать список идентификаторов, которые будут импортировать- ся с помощью выражения from module import *
. Идентификаторы внутри списка указыва- ются в виде строки. Создадим файл module3.py
(листинг 12.16).
Листинг 12.16. Использование атрибута __all__
# -*- coding: utf-8 -*- x, y, z, _s = 10, 80, 22, "Строка"
1 ... 18 19 20 21 22 23 24 25 ... 83
__all__ = ["x", "_s"]
Затем напишем программу, которая будет его импортировать (листинг 12.17).
Листинг 12.17. Код основной программы
# -*- coding: utf-8 -*- from module3 import * print(sorted(vars().keys())) # Получаем список всех идентификаторов input()
После запуска основной программы (с помощью двойного щелчка на значке файла) полу- чим следующий результат:
['__annotations__', '__builtins__', '__doc__', '__file__', '__loader__', '__name__',
'__package__', '__spec__', '_s', 'x']
Как видно из примера, были импортированы только переменные
_s и x
. Если бы мы не ука- зали идентификаторы внутри списка
__all__
, результат был бы другим:
['__annotations__', '__builtins__', '__doc__', '__file__', '__loader__', '__name__',
'__package__', '__spec__', 'x', 'y', 'z']
Обратите внимание на то, что переменная
_s в этом случае не импортируется, т. к. ее имя начинается с символа подчеркивания.
Глава 12. Модули и пакеты
237 12.3. Пути поиска модулей
До сих пор мы размещали модули в одной папке с файлом основной программы. В этом случае нет необходимости настраивать пути поиска модулей, т. к. папка с исполняемым файлом автоматически добавляется в начало списка путей. Получить полный список путей поиска позволяет следующий код:
>>> import sys # Подключаем модуль sys
>>> sys.path # path содержит список путей поиска модулей
Список из переменной sys.path содержит пути поиска, получаемые из следующих источ- ников:
путь к папке с файлом основной программы;
значение переменной окружения
PYTHONPATH
. Для добавления переменной в меню Пуск выбираем пункт Панель управления (или Настройка | Панель управления). В от- крывшемся окне выбираем пункт Система и щелкаем на ссылке Дополнительные параметры системы. Переходим на вкладку Дополнительно и нажимаем кнопку
Переменные среды. В разделе Переменные среды пользователя нажимаем кнопку
Создать. В поле Имя переменной вводим
PYTHONPATH
, а в поле Значение переменной задаем пути к папкам с модулями через точку с запятой — например,
C:\folder1;C:
\folder2
. Закончив, не забудем нажать кнопки ОK обоих открытых окон. После этого изменения перезагружать компьютер не нужно, достаточно заново запустить программу;
пути поиска стандартных модулей;
содержимое файлов с расширением pth
, расположенных в каталогах поиска стандартных модулей, — например, в каталоге
C:\Python36\Lib\site-packages
. Названия таких файлов могут быть произвольными, главное, чтобы они имели расширение pth
. Каждый путь
(абсолютный или относительный) должен быть расположен на отдельной строке.
Для примера создайте файл mypath.pth в каталоге
C:\Python36\Lib\site-packages со сле- дующим содержимым:
# Это комментарий
C:\folder1
C:\folder2
П
РИМЕЧАНИЕ
Обратите внимание на то, что каталоги должны существовать, в противном случае они не будут добавлены в список sys.path.
При поиске модуля список sys.path просматривается от начала к концу. Поиск прекраща- ется после первого найденного модуля. Таким образом, если в каталогах
C:\folder1
и
C:\folder2
существуют одноименные модули, то будет использоваться модуль из папки
C:\folder1
, т. к. он расположен первым в списке путей поиска.
Список sys.path можно изменять программно с помощью соответствующих методов. На- пример, добавить каталог в конец списка можно с помощью метода append()
, а в его нача- ло — с помощью метода insert()
(листинг 12.18).
Листинг 12.18. Изменение списка путей поиска модулей
# -*- coding: utf-8 -*- import sys sys.path.append(r"C:\folder1") # Добавляем в конец списка