Kodomo

Пользователь

Учебная страница курса биоинформатики,
год поступления 2010

Самодокументация. Тесты. Модули.

Кроме того, что программа выполняет свои функции, у неё бывает ещё и несколько других положительных качеств, которые она может уметь проявлять, например:

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

На самом деле, они очень сильно взаимосвязаны.

Первый и самый эффективный способ улучшать их оба одновременно – писать код программы чисто и ясно. Обычно для этого нужно:

Второй, весьма эффективный способ, состоит в том, чтобы для отдельных частей программы создавать автоматические тесты. Хорошо написанный набор автоматических тестов может заодно быть и хорошим описанием программы – и об этом тоже написано ниже.

Модули

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

Питонский файл, в котором лежит много функций (а может, заодно и описаний констант), называется модулем.

Мы уже умем их импортровать – import m делает вам доступным модуль m под именем m и функцию x из него под именем m.x. Ещё мы знаем, что from m import x делает доступной функцию x из модуля m сразу под именем x, при этом, из всего модуля нам становится доступной только она.

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

Теперь находясь в той же директории вы можете сказать import m, и получить доступ к тому, что вы положили в этот файл. Конструкция import ищет модули сначала в текущей директории, а затем в нескольких директориях, в которые установлен сам питон.1

if __name__ == "__main__"

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

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

   1 x = 1
   2 if __name__ == "__main__":
   3     print "I am standalone progam"
   4 else:
   5     print "I am module"

Если вы напишете такую программу и положите в файл m.py, то если вы его запустите, у вас на экране появится сообщение "I am standalone program", а если вы его проимпортируете, получится:

   1 >>> import m
   2 I am module
   3 >>> print m.x
   4 1

Самодокументация

Когда программа становится сложной, в ней становится осмысленно оставлять комментарии о том, чего хотел этой строкой сделать автор. В питоне есть несколько способов это делать.

Во-первых, есть комментарии. Комментарии в питоне начинаются с # и длятся до конца строки. Во всех остальных смыслах питон такие куски строк игнорирует:

   1 def return_1():
   2     return 1 # returns 1

– Это пример того, как НЕ надо поступать. В данном случае комментарий ничего в программе не поясняет. Комментарии к программам делят на несколько типов:

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

Поэтому в питоне не рекомендуется писать коментарии через #, а вместо этого есть другой способ:

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

   1 site_begin = 10
   2 site_end = 15
   3 
   4 def site_len(seq):
   5     """Return length of recognition site of sequence seq.
   6 
   7     Recognition site is alignment columns defined by global variables
   8     site_begin and site_end.
   9 
  10     Return number of non-gap symbols within the recognition site.
  11 
  12     Example:
  13     >>> site_len("LAGFLDADGYFQ--VR--I---INRERK")
  14     4
  15     """
  16     return len(seq[site_begin:site_end].replace("-", ""))

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

В таких описаниях функции принято:

Совершенно аналогичным образом, если текст модуля начинается с тройных кавычек, то это есть документация к модулю.

Вы можете читать документацию к своим модулям наравне с документацией к встроенным питонским модулям с помощью функции help. Например, если у вас в текущей директории есть модуль m (файл m.py), то вы можете сказать так:

   1 >>> import sys
   2 >>> help(sys.chdir)
   3 ...
   4 >>> import m
   5 >>> help(m)
   6 ...
   7 >>> help(m.x)
   8 ...

Тесты

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

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

В примере выше, если мы добавим в начало программы строчку

   1 import doctest

а в конец программы (после определения функции site_len) строчку

   1 doctest.testmod()

То питон нам выдаст:

**********************************************************************
File "t.py", line 12, in __main__.site_len
Failed example:
    site_len("LAGFLDADGYFQ--VR--I---INRERK")
Expected:
    4
Got:
    3
**********************************************************************
1 items had failures:
   1 of 1 in __main__.site_len
***Test Failed*** 1 failures.

И действительно, на выбранном диапазоне букв-то 3, а не 4.

В случае, если тесты прошли успешно, питон не будет печатать ничего.

Типичная традиция состоит в том, чтобы делать питонские модули, которые не являются самостоятельными программами, самотестирующими. Делается это так:

   1 import doctest
   2 
   3 ...
   4 
   5 if __name__ == "__main__":
   6     doctest.testmod()

  1. Любознательные могут увидеть список этих директорий в переменной sys.path, и почитать исходные коды большинства модулей питона. Правда, некоторые из них написаны не на питоне, а на языке Си, и их тексты читать сложнее. (1)