В программировании модуль - это часть программного обеспечения, имеющая определенный функционал. Например, при создании игры в пинг-понг один модуль будет отвечать за игровую логику, а другой модуль будет отвечать за рисование игры на экране. Каждый модуль представляет собой файл, который можно редактировать отдельно.
Написание модулей
Mодули в Python - это просто файлы Python с расширением .py. Имя модуля будет именем файла. Модуль Python может иметь набор функций, классов или переменных, определенных и реализованных. В приведенном выше примере у нас будет два файла:
mygame/
mygame/game.py
mygame/draw.py
Скрипт Python game.py
будет реализовывать игру. Он будет использовать функцию draw_game
из файла draw.py
, или, другими словами, модуль draw
, который реализует логику для рисования игры на экране.
Модули импортируются из других модулей с помощью команды import
. В этом примере скрипт game.py
может выглядеть примерно так:
# game.py
# import the draw module
import draw
def play_game():
...
def main():
result = play_game()
draw.draw_game(result)
#this means that if this script is executed, then main() will be executed
Модуль draw
может выглядеть примерно так:
# draw.py
def draw_game():
...
В этом примере модуль game
импортирует модуль draw
, что позволяет ему использовать функции, реализованные в этом модуле. Функция main
будет использовать локальную функцию play_game
для запуска игры, а затем выводить результат игры, используя функцию, реализованную в модуле draw
, называемую draw_game
. Чтобы использовать функцию draw_game
из модуля draw
, нам нужно указать, в каком модуле реализована функция, используя оператор точки. Чтобы сослаться на функцию draw_game
из game
модуля, нам нужно будет импортировать модуль draw
и только затем вызывать draw.draw_game()
.
Когда директива import draw
будет запущена, интерпретатор Python будет искать файл в каталоге, из которого был выполнен скрипт, по имени модуля с префиксом .py
, поэтому в нашем случае он попытается найти draw.py
. Если он найдет его, то импортирует. Если нет, он продолжит искать встроенные модули.
ВВозможно, вы заметили, что при импорте модуля появляется файл .pyc, который представляет собой скомпилированный файл Python. Python компилирует файлы в байт-код Python, так что ему не придется анализировать файлы при каждой загрузке модулей. Если файл .pyc существует, он загружается вместо файла .py, но этот процесс прозрачен для пользователя.
Импорт объектов модуля в текущее пространство имен
Мы также можем импортировать функцию draw_game
непосредственно в пространство имен основного скрипта, используя команду from
.
# game.py
# import the draw module
from draw import draw_game
Возможно, вы заметили, что в этом примере draw_game
не предшествует имени модуля, из которого он импортирован, потому что мы указали имя модуля в команде import
.
Преимущества использования этой записи в том, что функции внутри текущего модуля проще использовать, поскольку вам не нужно указывать, из какого модуля поступает функция. Однако ни в одном пространстве имен не может быть двух объектов с одинаковым именем, поэтому команда import
может заменить существующий объект в пространстве имен.
Импорт всех объектов из модуля
Мы также можем использовать команду import *
для импорта всех объектов из определенного модуля, например:
# game.py
# import the draw module
from draw import *
Это может быть немного рискованно, так как изменения в модуле могут повлиять на модуль, который его импортирует, но это более короткий вариант и также не требует указания объектов, которые вы хотите импортировать из модуля.
Пользовательское имя импорта
Мы также можем загружать модули под любым именем. Это полезно, когда мы хотим импортировать модуль условно, чтобы использовать то же имя в остальной части кода.
Например, если у вас есть два draw
модуля с немного разными именами, вы можете сделать следующее:
# game.py
# import the draw module
if visual_mode:
# in visual mode, we draw using graphics
import draw_visual as draw
else:
# in textual mode, we print out text
import draw_textual as draw
Инициализация модуля
При первой загрузке модуля в работающий скрипт Python он инициализируется однократным выполнением кода в модуле Если другой модуль в вашем коде снова импортирует тот же модуль, он будет загружен не дважды, а только один раз - поэтому локальные переменные внутри модуля действуют как «одиночные» - они инициализируются только один раз.
Полезно знать - это означает, что вы можете положиться на такое поведение для инициализации объектов. Например:
# draw.py
def draw_game():
# when clearing the screen we can use the main screen object initialized in this module
clear_screen(main_screen)
...
def clear_screen(screen):
...
class Screen():
...
initialize main_screen as a singleton
Расширение пути загрузки модуля
Есть несколько способов сказать интерпретатору Python, где искать модули, кроме используемых по умолчанию, которыми является локальный каталог и встроенные модули. Вы можете использовать переменную окружения PYTHONPATH
чтобы указать дополнительные каталоги для поиска модулей, например так:
PYTHONPATH=/foo python game.py
Настоящим будет запущен game.py
, что позволит скрипту загрузить модули из каталога foo
, а также из локального каталога.
Другим методом является функция sys.path.append
. Вы можете выполнить его до запуска команды import
:
sys.path.append("/foo")
Это добавит каталог foo
в список путей для поиска модулей.
Изучение встроенных модулей
Проверьте полный список встроенных модулей в стандартной библиотеке Python здесь.
При изучении модулей в Python пригодятся две очень важные функции - функции dir
и help
.
Если мы хотим импортировать модуль urllib
, , который позволяет нам создавать данные для чтения из URL, мы просто import
импортируем модуль:
# import the library
import urllib
use it
Мы можем посмотреть, какие функции реализованы в каждом модуле, используя функцию dir
:
import urllib
dir(urllib)
#['ContentTooShortError', 'FancyURLopener', 'MAXFTPCACHE', 'URLopener', '__all__', '__builtins__',
'__doc__', '__file__', '__name__', '__package__', '__version__', '_ftperrors', '_get_proxies',
'_get_proxy_settings', '_have_ssl', '_hexdig', '_hextochr', '_hostprog', '_is_unicode', '_localhost',
'_noheaders', '_nportprog', '_passwdprog', '_portprog', '_queryprog', '_safe_map', '_safe_quoters',
'_tagprog', '_thishost', '_typeprog', '_urlopener', '_userprog', '_valueprog', 'addbase', 'addclosehook',
'addinfo', 'addinfourl', 'always_safe', 'basejoin', 'c', 'ftpcache', 'ftperrors', 'ftpwrapper', 'getproxies',
'getproxies_environment', 'getproxies_macosx_sysconf', 'i', 'localhost', 'main', 'noheaders', 'os',
'pathname2url', 'proxy_bypass', 'proxy_bypass_environment', 'proxy_bypass_macosx_sysconf', 'quote',
'quote_plus', 'reporthook', 'socket', 'splitattr', 'splithost', 'splitnport', 'splitpasswd', 'splitport',
'splitquery', 'splittag', 'splittype', 'splituser', 'splitvalue', 'ssl', 'string', 'sys', 'test', 'test1',
'thishost', 'time', 'toBytes', 'unquote', 'unquote_plus', 'unwrap', 'url2pathname', 'urlcleanup', 'urlencode',
'urlopen', 'urlretrieve']
Когда мы находим в модуле функцию, которую хотим использовать, мы можем получить дополнительную информацию о ней, используя функцию help
внутри интерпретатора Python:
help(urllib.urlopen)
Написание пакетов
Пакеты - это пространства имен, которые содержат несколько пакетов и сами модули. Это просто каталоги, но с изюминкой.
Каждый пакет в Python является каталогом, который ДОЛЖЕН содержать специальный файл с именем __init__.py
. Этот файл может быть пустым, что означает, что каталог, который он содержит, является пакетом Python, поэтому его можно импортировать так же, как импортировать модуль.
Если мы создадим каталог с именем foo
, который помечает имя пакета, мы можем затем создать модуль внутри этого пакета с именем bar
. Мы также не должны забывать добавить файл __init__.py
в каталог foo
.
Чтобы использовать модуль bar
, мы можем произвести импорт двумя способами:
import foo.bar
или:
from foo import bar
В первом методе мы должны использовать префикс foo
всякий раз, когда получаем доступ к bar
. Во втором методе мы этого не делаем, потому что мы импортируем модуль в пространство имен нашего модуля.
Файл __init__.py
также может решить, какие модули пакет экспортирует как API, сохраняя при этом другие модули внутренними, переопределив переменную __all__
например, следующим образом:
__init__.py:
Упражнение
В этом упражнении вам нужно будет распечатать отсортированный по алфавиту список всех функций в модуле re
, которые содержат слово find
.