Простой Python — страница 19 из 66

Теперь используйте свою версию Python, чтобы запустить эту программу. Вот так может выглядеть окно терминала в операционных системах Linux или Mac OS X, использующее стандартную программу оболочки:

$ python test2.py

Program arguments: ['test2.py']

$ python test2.py tra la la

Program arguments: ['test2.py', 'tra', 'la', 'la']

Модули и оператор import

Мы собираемся перейти на новый уровень — создание и использование кода более чем из одного файла. Модуль — это всего лишь файл, содержащий код Python.

Текст этой книги организован в иерархию: слова, предложения, абзацы и главы. В противном случае он стал бы нечитаемым спустя пару страниц. У кода имеется подобная организация: типы данных похожи на слова, операторы и выражения — это предложения, функции — это абзацы, а модули — это главы. Продолжу аналогию: когда я говорю, что что-то будет более подробно рассмотрено в главе 8, в программировании это было бы похоже на отсылку к коду другого модуля.

Мы ссылаемся на код других модулей с помощью оператора import. Оно позволяет получить доступ к коду и переменным этого модуля из вашей программы.

Импортируем модуль

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

Основная программа выглядит так (назовем ее weatherman.py):

import report

description = report.get_description()

print("Today's weather: ", description)

А ее модуль (report.py) — так:

def get_description():··# смотрите строку документации

····"""Return random weather, just like the pros"""

····from random import choice

····possibilities = ['rain', 'snow', 'sleet', 'fog', 'sun', 'who knows']

····return choice(possibilities)

Если вы поместите оба этих файла в один каталог и укажете Python запустить файл weatherman.py в качестве основной программы, он обратится к модулю report и запустит его функцию get_description(). Мы написали эту версию функции get_description() так, чтобы она возвращала случайную строку из списка, которую выведет на экран основная программа:

$ python weatherman.py

Today's weather: who knows

$ python weatherman.py

Today's weather: sun

$ python weatherman.py

Today's weather: sleet

Мы использовали оператор import в двух местах.

• В основной программе weatherman.py, импортируемой модулем report.

• В файле модуля report.py функция get_description() импортирует функцию choice из стандартного модуля Python random.

Мы также использовали эти операторы двумя разными способами.

• Основная программа делала вызов import report и затем вызывала функцию report.get_description().

• Функция get_description() из модуля report.py содержит вызовы from random import choice и choice(possibilities).

В первом случае мы импортировали модуль report целиком, при этом нам нужно было добавить префикс report., чтобы вызвать функцию get_description(). После этого оператора import все содержимое файла report.py становится доступным основной программе, нужно лишь ставить перед именем вызываемой функции префикс report.. Путем уточнения содержимого модуля с помощью его имени мы избегаем возникновения неприятных конфликтов именования. В каком-то другом модуле также может быть функция get_descpirtion(), и мы не вызовем ее по ошибке.

Во втором случае мы находимся внутри функции и знаем, что существует только одна функция с именем choice, поэтому импортируем функцию choice() непосредственно из модуля random. Мы могли бы написать функцию как следующий сниппет, который возвращает случайный результат:

def get_description():

····import random

····possibilities = ['rain', 'snow', 'sleet', 'fog', 'sun', 'who knows']

····return random.choice(possibilities)

Как и для многих других аспектов программирования, выбирайте стиль, который кажется вам наиболее прозрачным. Имя функции, перед которым стоит имя модуля (random.choice), использовать безопаснее, однако из-за этого придется набирать немного больше текста.

Эти примеры применения функции get_description() продемонстрировали варианты того, что можно импортировать, но не показали, где следует выполнять импортирование, — в них import вызывался изнутри функции. Мы могли бы импортировать random из другой функции:

>>> import random

>>> def get_description():

…····possibilities = ['rain', 'snow', 'sleet', 'fog', 'sun', 'who knows']

…····return random.choice(possibilities)

>>> get_description()

'who knows'

>>> get_description()

'rain'

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

Импортируем модуль с другим именем

В нашей основной программе weatherman.py мы делали вызов import report. Но что, если у вас есть другой модуль с таким же именем или вы хотите использовать более короткое или простое имя? В такой ситуации можете выполнить импорт с помощью псевдонима. Используем псевдоним wr:

import report as wr

description = wr.get_description()

print("Today's weather: ", description)

Импортируем только самое необходимое

С помощью Python вы можете импортировать одну или несколько частей модуля. Каждая часть может сохранить свое оригинальное имя, или же вы можете дать ей alias. Для начала импортируем функцию get_description() из модуля report с помощью его оригинального имени:

from report import get_description

description = get_description()

print("Today's weather: ", description)

Теперь импортируем ее как do_it:

from report import get_description as do_it

description = do_it()

print("Today's weather: ", description)

Каталоги поиска модулей

Где Python ищет файлы для импорта? Он использует список имен каталогов и ZIP-архив, хранящийся в стандартном модуле sys, как переменную path. Вы можете получить доступ к этому списку и изменить его. Вот так выглядит значение переменной sys.path в Python 3.3 в моей версии операционной системы Mac:

>>> import sys

>>> for place in sys.path:

…·····print(place)

/Library/Frameworks/Python.framework/Versions/3.3/lib/python33.zip

/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3

/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/plat-darwin

/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/lib-dynload

/Library/Frameworks/Python.framework/Versions/3.3/lib/python3.3/site-packages

Пустое место в начале вывода содержит в себе строку '', которая символизирует текущий каталог. Если строка '' находится первой в sys.path, Python сначала выполнит поиск в текущем каталоге, когда вы попробуете что-то импортировать: import report выглядит как report.py.

Будет использован первый найденный модуль. Это означает, что, если вы определите модуль с именем random и он будет найден раньше оригинального модуля, вы не получите доступ к стандартной библиотеке random.

Пакеты

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

Возможно, нам нужны разные типы прогнозов погоды: на следующий день и следующую неделю. В качестве одного из вариантов мы можем создать папку с именем sources, а внутри нее — два модуля: daily.py и weekly.py. Каждый из них содержит функцию forecast. Версия на каждый день возвращает строку, а версия на каждую неделю — список из семи строк.