Функция main() для Python. Гвидо ван Россум. Перевод: Орехов А.И.

Перевод статьи Гвидо ван Россума, рассказывающей о том, как следует оформлять функцию main().

Хочу предложить программистам функцию main(), которую удобно использовать в различном контексте. Например в интерактивном режиме Python, когда вам хочется поэкспериментировать.

В свое время, я определял функцию main() различным образом. Приблизительно так:

"""Описание модуля.

Подробное описание использования.
"""
import sys
import getopt

def main():
    # Разбираем аргументы командной строки
    try:
        opts, args = getopt.getopt(sys.argv[1:], "h", ["help"])
    except getopt.error, msg:
        print msg
        print "для справки используйте --help"
        sys.exit(2)
    # process options
    for o, a in opts:
        if o in ("-h", "--help"):
            print __doc__
            sys.exit(0)
    # Анализируем
    for arg in args:
        process(arg) # process() определен в другом месте

if __name__ == "__main__":
    main()

Я уверен, что многие пишут нечто подобное main() функции. Несколько предложений, которые сделают эту функцию более гибкой. Тем более, что синтаксический анализ опций становится все более сложным.

Во первых, добавим дополнительный аргумент argv. Так, чтобы можно было вызывать функцию в интерактивном режиме:

def main(argv=None):
    if argv is None:
        argv = sys.argv
        # и т.д. заменяя sys.argv на argv в getopt запросах

Обратите внимание, что мы заполняем значения по умолчанию динамически. Это более гибко, чем:

def main(argv=sys.argv):
    # и т.д.

Таким образом теперь мы можем изменить параметры вызова в любой момент времени.

Вызов sys.exit() закрывает сессию интерпретатора. Доработаем программу:

if __name__ == "__main__":
    sys.exit(main())

Вызов sys.exit(main()) вернет результат функции.

Другое усовершенствование касается использования исключения Usage(), которое мы перехватываем в main:

import sys
import getopt

class Usage(Exception):
    def __init__(self, msg):
        self.msg = msg

def main(argv=None):
    if argv is None:
        argv = sys.argv
    try:
        try:
            opts, args = getopt.getopt(argv[1:], "h", ["help"])
        except getopt.error, msg:
             raise Usage(msg)
        # more code, unchanged
    except Usage, err:
        print >>sys.stderr, err.msg
        print >>sys.stderr, "for help use --help"
        return 2

if __name__ == "__main__":
    sys.exit(main())

Теперь мы имеем единственную точку выхода из функции, что предпочтительнее множественных return 2. Это также облегчает повторный анализ параметров: raise Usage вызывается просто во вспомогательной функции.

Вы можете возразить, что можно перенести конструкцию try/except из main() в конец модуля (if __name__ == "__main__": ...). Но это привело бы к возникновению ошибки при вызове в интерактивном режиме интерпретатора.

Однако, обобщение может быть полезным: определите другое исключение (возможно Error), которое обрабатывается так же, как и Usage, но возвращает 1. Его можно применять для ожидаемых ошибок типа отказа открыть необходимые файлы. Не ситаксические ошибки командной строки, но ожидаемые ситуации. Т.к. traceback не очень дружественное средство в таких случаях.

Какой прием написания main() нравится вам больше?

Спорьте и возражайте!

Имеете мнение? Читатели уже зарегистрировали 3 коментария в weblog. Почему бы вам не добавить ваш?

RSS рассылка

Если вы хотите быть в курсе последних изменений weblog, подпишитесь на RSS рассылку

Гвидо ван Россум - создатель Python, одного из важнейших языков программирования в Сети и вне ее. Сообщество Питонцев называет его Великодушный Пожизненный Диктатор (заголовок взят из сериала Монти Пайтон). Он переехал из Нидерландов в США в 1995 году, где и женился. Живет с семьей на севере Вирджинии вблизи Вашингтона. Работает в корпорации Zope. Он и его коллеги из PythonLabs продолжают совершенствования языка.

This weblog entry is Copyright 2003 Guido van Rossum. All rights reserved.