Главная страница
Навигация по странице:

  • Пример: поведение по умолчанию

  • Пример: перехват встроенных исключений

  • Инструкция try/finally

  • Пример: реализация завершающих действий с помощью инструкции try/finally

  • Объединенная инструкция try/except/finally

  • Пример использования объединенной инструкции try

  • Математический анализ. 3е издание


    Скачать 4.86 Mb.
    Название3е издание
    АнкорМатематический анализ
    Дата04.02.2022
    Размер4.86 Mb.
    Формат файлаpdf
    Имя файлаpython_01.pdf
    ТипДокументы
    #351981
    страница87 из 98
    1   ...   83   84   85   86   87   88   89   90   ...   98
    714
    Глава 27. Основы исключений передано обработчику исключения ниже (тонко, но верно!). При явном использовании выражения else логика выполнения становится более очевидной и гарантируется, что обработчики исключений будут вызы
    ваться только для обработки истинных ошибок в блоке, обернутом ин
    струкцией try, а не при выполнении действий, предусматриваемых в блоке else.
    Пример: поведение по умолчанию
    Поскольку объяснить порядок выполнения программы проще на язы
    ке Python, чем на естественном языке, рассмотрим несколько приме
    ров, иллюстрирующих основы исключений. Я уже упоминал, что ис
    ключения, не перехваченные инструкциями try, распространяются до самого верхнего уровня процесса и запускают логику обработки ис
    ключений по умолчанию (то есть интерпретатор аварийно завершает работающую программу и выводит стандартное сообщение об ошиб
    ке). Рассмотрим пример. При попытке запустить следующий модуль
    bad.py
    возникает исключение деления на ноль:
    def gobad(x, y):
    return x / y def gosouth(x):
    print gobad(x, 0)
    gosouth(1)
    Так как программа сама не обрабатывает это исключение, интерпрета
    тор завершает ее и выводит сообщение:
    1
    % python bad.py
    Traceback (most recent call last):
    File "bad.py", line 7, in
    gosouth(1)
    File "bad.py", line 5, in gosouth print gobad(x, 0)
    File "bad.py", line 2, in gobad return x / y
    ZeroDivisionError: integer division or modulo by zero
    (ZeroDivisionError: целочисленное деление или деление по модулю на ноль)
    Сообщение состоит из содержимого стека и имени (с дополнительны
    ми данными) исключения. В содержимом стека перечислены все стро
    ки, которые были активны в момент появления исключения, в поряд
    ке от более старых к более новым. Обратите внимание: так как в дан
    ном случае мы работаем в командной строке системы, а не в интерак
    1
    Текст сообщений и отладочная информация время от времени немного из
    меняются. Поэтому не надо беспокоиться, если ваши сообщения не соответ
    ствуют в точности тем, что приводятся здесь. Например, когда я запускал этот пример в среде IDLE, входящей в состав Python 2.5, в тексте сообще
    ния выводились полные пути к файлам.

    Инструкция try/except/else
    715
    тивной оболочке интерпретатора, имена файлов и номера строк содержат полезную для нас информацию. Например, здесь видно, что ошибка произошла во 2 строке в файле bad.py, в инструкции return.
    Так как интерпретатор Python определяет и сообщает обо всех ошиб
    ках, появившихся во время выполнения программы, возбуждая ис
    ключения, эти исключения тесно связаны с идеями обработки ошибок и отладки вообще. Если вы работали с примерами из этой книги, вы без сомнений встречались с несколькими исключениями – даже опе
    чатки нередко приводят к возбуждению исключения SyntaxError или других при импортировании и выполнении файла (то есть, когда за
    пускается компилятор). По умолчанию интерпретатор выводит полез
    ное информативное сообщение, как показано выше, которое позволяет легко отыскать источник проблем.
    Чаще всего для разрешения проблем достаточно стандартных сообще
    ний об ошибках. Для более надежной отладки своих программ вы мо
    жете перехватывать исключения с помощью инструкций try или ис
    пользовать средства отладки, которые будут представлены в главе 29,
    такие как модуль pdb из стандартной библиотеки.
    Пример: перехват встроенных исключений
    Обработка исключений, которая выполняется интерпретатором по умолчанию, зачастую удовлетворяет всем нашим потребностям, осо
    бенно для программного кода верхнего уровня, где ошибки должны приводить к немедленному завершению программы. Для большинства программ нет никакой необходимости предусматривать какието осо
    бые варианты обработки ошибок.
    Однако иногда бывает необходимо перехватить ошибку и выполнить восстановительные действия после нее. Если для вас нежелательно,
    чтобы программа завершалась, когда интерпретатор возбуждает ис
    ключение, достаточно просто перехватить его, обернув участок про
    граммы в инструкцию try. Это очень важная возможность для таких программ, как серверы сети, которые должны продолжать работать постоянно. Например, следующий фрагмент перехватывает и обраба
    тывает исключение TypeError, которое возбуждается интерпретатором при попытке выполнить операцию конкатенации для списка и строки
    (оператор + требует, чтобы слева и справа были указаны последова
    тельности одного и того же типа):
    def kaboom(x, y):
    print x + y # Возбуждает исключение TypeError
    try:
    kaboom([0,1,2], "spam")
    except TypeError: # Исключение перехватывается и обрабатывается здесь
    print 'Hello world!'
    print 'resuming here' # Программа продолжает работу, независимо от того,
    # было ли исключение или нет

    716
    Глава 27. Основы исключений
    Когда в функции kaboom возникает исключение, управление передает
    ся предложению except в инструкции try, где выводится текст сообще
    ния. После того как исключение перехватывается, оно становится не
    актуальным, поэтому программа продолжает выполнение ниже инст
    рукции try вместо того, чтобы завершиться. Программный код дейст
    вительно обрабатывает и ликвидирует ошибку.
    Обратите внимание: как только ошибка будет перехвачена, выполне
    ние продолжается с того места, где ошибка была перехвачена (то есть после инструкции try), – нет никакой возможности вернуться к тому месту, где возникла ошибка (в данном случае – в функцию kaboom).
    В некотором смысле это делает исключения более похожими на инст
    рукции перехода, чем на вызовы функций – нет никакой возможности вернуться к программному коду, вызвавшему ошибку.
    Инструкция try/finally
    Другая разновидность инструкции try специализируется на выполне
    нии завершающих действий. Если в инструкцию try включено предло
    жение finally, интерпретатор всегда будет выполнять этот блок инст
    рукций при «выходе» из инструкции try независимо от того, произош
    ло ли исключение во время выполнения инструкций в блоке try. Об
    щая форма этой инструкции имеет следующий вид:
    try:
    <инструкции> # Выполнить эти действия первыми
    finally:
    <инструкции> # Всегда выполнять этот блок кода при выходе из инструкции
    При использовании этой инструкции интерпретатор Python в первую очередь выполняет инструкции в блоке try. Что произойдет дальше,
    зависит от того, возникло ли исключение в блоке try:

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

    Если во время выполнения инструкций в блоке try возникло ис
    ключение, интерпретатор также выполнит инструкции в блоке fi
    nally
    , но после этого исключение продолжит свое распространение до вышестоящей инструкции try или до обработчика исключений по умолчанию – программа не будет выполняться вслед за инструк
    цией try. То есть инструкции в блоке finally будут выполнены, да
    же если исключение будет возбуждено, но в отличие от предложе
    ния except, finally не завершает распространение исключения – оно остается актуальным после выполнения блока finally.
    Форма try/finally бывает удобна, когда необходимо гарантировать вы
    полнение некоторых действий независимо от реакции программы на исключение. С практической точки зрения эта форма инструкции по

    Инструкция try/finally
    717
    зволяет определять завершающие действия, которые должны выпол
    няться всегда, такие как закрытие файлов или закрытие соединений с сервером.
    Обратите внимание: в Python 2.4 и в более ранних версиях предложе
    ние finally не может использоваться в той же инструкции try, где уже используется предложение except или else, поэтому форму try/finally лучше считать отдельной формой инструкции при работе со старыми версиями. Однако в Python 2.5 предложение finally может присутст
    вовать в инструкции try вместе с предложениями except и else, поэто
    му в настоящее время существует единая инструкция try, которая мо
    жет употребляться с несколькими необязательными предложениями
    (вскоре мы поговорим об этом подробнее). Однако какую бы версию
    Python вы не использовали, назначение предложения funally остается прежним – определить завершающие действия, которые должны вы
    полняться всегда, независимо от возникновения исключений.
    Как будет показано далее в этой главе, в версии Python 2.6, инст
    рукция with и контекстные менеджеры обеспечивают объектно
    ориентированный подход к выполнению аналогичных завершаю
    щих действий, но кроме того, эта инструкция поддерживает воз
    можность выполнения действий по инициализации.
    Пример: реализация завершающих действий
    с помощью инструкции try/finally
    Выше мы видели несколько простых примеров применения инструк
    ции try/finally. Ниже приводится более близкий к реальности при
    мер, иллюстрирующий типичное применение этой инструкции:
    class MyError(Exception): pass def stuff(file):
    raise MyError()
    file = open('data', 'w') # Открыть файл для вывода
    try:
    stuff(file) # Возбуждает исключение
    finally:
    file.close() # Всегда закрывать файл, чтобы вытолкнуть буферы
    ... # Продолжить с этого места,
    # только если не было исключения
    В этом фрагменте мы обернули вызов функции в инструкцию try,
    с предложением finally, чтобы гарантировать, что файл будет закрыт при любых обстоятельствах, независимо от того, будет возбуждено ис
    ключение в функции или нет. При таком подходе расположенный да
    лее программный код может быть уверен, что содержимое выходных буферов файла было вытолкнуто из памяти на диск. Подобная структу
    ра программного кода может гарантировать закрытие соединения с сер
    вером и т. д.

    718
    Глава 27. Основы исключений
    Функция в этом примере не делает ничего полезного (она просто возбу
    ждает исключение), но обернув ее в инструкцию try/finally, мы гаран
    тируем, что действия по завершению будут выполняться всегда. На
    помню еще раз, что интерпретатор всегда выполняет программный код в блоке finally независимо от того, было возбуждено исключение в бло
    ке try или нет.
    1
    Когда функция в этом примере возбуждает исключение, управление передается обратно инструкции try и начинает выполняться блок fi
    nally
    , в котором производится закрытие файла. После этого исключе
    ние продолжает свое распространение либо пока не встретит другую инструкцию try, либо пока не будет достигнут обработчик по умолча
    нию, который выведет стандартное сообщение об ошибке и остановит работу программы; инструкция, находящая ниже инструкции try, ни
    когда не будет достигнута. Если бы функция в этом примере не возбу
    ждала исключение, программа точно так же выполнила бы блок final
    ly
    , чтобы закрыть файл, и затем продолжила бы свое выполнение ни
    же инструкции try.
    Кроме того, обратите внимание, что здесь исключение опять определе
    но как класс – как будет показано в следующей главе, в настоящее вре
    мя все исключения должны быть классами.
    Объединенная инструкция try/except/finally
    Во всех версиях Python, вышедших до версии 2.5 (в течение первых
    15 лет жизни, или чтото около того), инструкция try существовала в двух разновидностях, и в действительности имелось две отдельные инструкции. Мы могли либо использовать предложение finally, чтобы гарантировать выполнение завершающего программного кода, либо писать блоки except, чтобы перехватывать определенные исключения и выполнять действия по восстановлению после них и, при желании,
    использовать предложение else, которое выполняется в случае отсут
    ствия исключений.
    То есть предложение finally нельзя было смешивать с предложениями except и else. Такое положение дел сохранялось отчасти изза проблем с реализацией, а отчасти изза неясности смысла такого смешивания –
    перехват и восстановление после исключений выглядит никак не свя
    занным с выполнением действий по завершению.
    Однако в Python 2.5 (эта версия Python используется в данном изда
    нии книги) две инструкции были объединены. Сейчас у нас имеется
    1
    Если, конечно, сам интерпретатор не завершит свою работу аварийно. Раз
    работчики Python упорно трудятся над тем, чтобы избежать подобного раз
    вития событий, проверяя все возможные ошибки во время работы. Полное обрушение программы вместе с интерпретатором часто происходит изза ошибок в расширениях, написанных на языке C, которые выполняются не под управлением Python.

    Объединенная инструкция try/except/finally
    719
    возможность смешивать предложения funally, except и else в одной и той же инструкции. То есть теперь мы можем написать инструкцию,
    имеющую следующий вид:
    try:
    основное действие
    except Exception1:
    обработчик1
    except Exception2:
    обработчик2
    else:
    блок else
    finally:
    блок finally
    Первым, как обычно, выполняется программный код в блоке основное
    действие
    . Если при выполнении этого блока возбуждается исключение,
    выполняется проверка всех блоков except, одного за другим, в поисках блока, соответствующего возникшему исключению. Если было возбу
    ждено исключение Exception1, будет выполнен блок обработчик1, ис
    ключение Exception2 приведет к запуску обработчика2 и т. д. Если ис
    ключение не было возбуждено, будет выполнен блок else.
    Независимо от того, что происходило раньше, блок finally будет вы
    полнен только после выполнения основных действий, и после обработ
    ки любых возникших исключений. В действительности, блок finally
    будет выполнен, даже если исключение возникнет в самом обработчи
    ке исключения или в блоке else.
    Как всегда, предложение finally не прекращает распространение ис
    ключения – если к моменту выполнения блока finally имеется актив
    ное исключение, оно продолжает свое распространение после выпол
    нения блока finally и управление передается кудато в другое место программы (другой инструкции try или обработчику по умолчанию).
    Если к моменту, когда блок finally будет выполнен, нет активного ис
    ключения, выполнение программы продолжится сразу же вслед за ин
    струкцией try.
    Таким образом, блок finally выполняется всегда, когда:

    В блоке основного действия возникло исключение и было обработано.

    В блоке основного действия возникло исключение и не было обрабо
    тано.

    В блоке основного действия не возникло исключение.

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

    720
    Глава 27. Основы исключений
    Объединение finally и except вложением
    До появления версии Python 2.5 существовала возможность объеди
    нять предложения finally и except в инструкции try за счет вложения инструкции try/except в блок try инструкции try/finally (более полно этот прием будет рассматриваться в главе 29). В действительности фрагмент ниже имеет тот же эффект, что и новая форма инструкции,
    представленная в предыдущем разделе:
    try:
    try:
    основное действие
    except Exception1:
    обработчик1
    except Exception2:
    обработчик2
    else:
    нет ошибок
    finally:
    завершающие действия
    Здесь также блок finally всегда выполняется при выходе из инструкции try независимо от того, что произошло в блоке основного действия, и не
    зависимо от того, выполнялись ли обработчики исключений во вложен
    ной инструкции try (представьте, как в этом случае будут развиваться четыре варианта событий, перечисленные выше, и вы увидите, что все будет выполняться точно так же). Однако этот эквивалент выглядит ме
    нее понятным, чем новая, объединенная форма инструкции. Смешан
    ная форма инструкции проще в написании и выглядит понятнее, поэто
    му такая форма записи считается в настоящее время предпочтительной.
    Пример использования объединенной инструкции try
    Ниже приводится пример использования объединенной формы инст
    рукции try. Здесь представлены четыре типичных варианта с инструк
    циями print, описывающими значение каждого из них:
    print '' * 30, '\nEXCEPTION RAISED AND CAUGHT'
    try:
    x = 'spam'[99]
    except IndexError:
    print 'except run'
    finally:
    print 'finally run'
    print 'after run'
    print '' * 30, '\nNO EXCEPTION RAISED'
    try:
    x = 'spam'[3]
    except IndexError:
    print 'except run'

    Объединенная инструкция try/except/finally
    721
    finally:
    print 'finally run'
    print 'after run'
    print '' * 30, '\nNO EXCEPTION RAISED, ELSE RUN'
    try:
    x = 'spam'[3]
    except IndexError:
    print 'except run'
    else:
    print 'else run'
    finally:
    print 'finally run'
    print 'after run'
    print '' * 30, '\nEXCEPTION RAISED BUT NOT CAUGHT'
    try:
    x = 1 / 0
    except IndexError:
    print 'except run'
    finally:
    print 'finally run'
    print 'after run'
    После запуска этот пример выводит на экран следующий ниже текст.
    Исследуйте программный код, чтобы понять, как работает каждый из вариантов:
    
    EXCEPTION RAISED AND CAUGHT
    except run finally run after run
    
    NO EXCEPTION RAISED
    finally run after run
    
    NO EXCEPTION RAISED, ELSE RUN
    else run finally run after run
    
    EXCEPTION RAISED BUT NOT CAUGHT
    finally run
    Traceback (most recent call last):
    File "C:/Python25/mergedexc.py", line 32, in
    x = 1 / 0
    ZeroDivisionError: integer division or modulo by zero
    (ZeroDivisionError: целочисленное деление или деление по модулю на ноль)
    Этот пример для возбуждения исключений в основном действии ис
    пользует встроенные операции и полагается на тот факт, что интер

    1   ...   83   84   85   86   87   88   89   90   ...   98


    написать администратору сайта