Начните изучать Python с помощью бесплатного курса Введение в Python от онлайн-института Кодкамп.

Модули и пакеты


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

Написание модулей

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
if __name__ == '__main__':
    main()

Модуль draw может выглядеть примерно так:

# draw.py

def draw_game():
    ...

def clear_screen(screen):
    ...

В этом примере модуль 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

def main():
    result = play_game()
    draw_game(result)

Возможно, вы заметили, что в этом примере draw_game не предшествует имени модуля, из которого он импортирован, потому что мы указали имя модуля в команде import.

Преимущества использования этой записи в том, что функции внутри текущего модуля проще использовать, поскольку вам не нужно указывать, из какого модуля поступает функция. Однако ни в одном пространстве имен не может быть двух объектов с одинаковым именем, поэтому команда import может заменить существующий объект в пространстве имен.

Импорт всех объектов из модуля

Мы также можем использовать команду import * для импорта всех объектов из определенного модуля, например:

# game.py
# import the draw module
from draw import *

def main():
    result = play_game()
    draw_game(result)

Это может быть немного рискованно, так как изменения в модуле могут повлиять на модуль, который его импортирует, но это более короткий вариант и также не требует указания объектов, которые вы хотите импортировать из модуля.

Пользовательское имя импорта

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

Например, если у вас есть два 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

def main():
    result = play_game()
    # this can either be visual or textual depending on visual_mode
    draw.draw_game(result)

Инициализация модуля

При первой загрузке модуля в работающий скрипт 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
main_screen = Screen()

Расширение пути загрузки модуля

Есть несколько способов сказать интерпретатору 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
urllib.urlopen(...)

Мы можем посмотреть, какие функции реализованы в каждом модуле, используя функцию 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:

__all__ = ["bar"]

Упражнение

В этом упражнении вам нужно будет распечатать отсортированный по алфавиту список всех функций в модуле re, которые содержат слово find.

import re # Your code goes here import re # Your code goes here find_members = [] for member in dir(re): if "find" in member: find_members.append(member) print(sorted(find_members)) test_object('find_members') success_msg('Great work!')

Этот сайт поддерживается онлайн-институтом Кодкамп. Кодкамп предлагает интерактивные онлайн-курсы по Python для развития цифровых навыков. Присоединяйтесь к тысячам других студентов и начните изучать Python уже сегодня!

Copyright © pythontuts.ru