На прошлой лекции мы определяли исключительную ситуацию, как ситуацию, возникающую в процессе выполнения программы, когда корректность программы нарушается. Это правильное определение, но трудно проверяемое на практике. Построение предикатов, использование операторов assert не самый простой способ обнаружения нарушений корректной работы. Чаще всего некорректное поведение программы обнаруживается, когда программа не может выполнить предусмотренную операцию. Примеров масса: не найден в указанном месте затребованный файл, возникла ошибка чтения или записи данных при работе с внешним источником данных, ошибка возникла при попытке деления на ноль или при извлечении квадратного корня из отрицательного числа, при попытке выполнить операцию сложения над операндами, над которыми эта операция не определена. Все эти ситуации являются исключительными, при выполнении любой программы.
В большинстве современных языков программирования появился инструментарий, позволяющий своевременно обнаруживать и должным образом обрабатывать исключительные ситуации, по какой-либо причине они не появились. В Python , как и в других ОО языках программирования, этот инструментарий построен на объектных принципах.
Для программиста исключительная ситуация - это объект, класс которого принадлежит обширному семейству классов, связанных отношением наследования. Эти классы описывают разнообразные исключительные ситуации, которые могут возникать при выполнении программ. Наследование - это прекрасный способ классификации объектов.
Семейство классов, описывающих исключения (Exception), содержит многочисленные встроенные классы и классы, создаваемые программистом. Прародителем всех встроенных классов семейства является класс BaseException, описывающий исключения любого типа. Его потомки - задают специализированные исключения. У этого класса четыре прямых потомка. Три потомка определяют исключения, порожденные устройствами компьютера, например, клавиатурой. Для нас наибольший интерес представляет четвертый потомок - класс Exception. Этот класс является родителем для более чем полусотни встроенных классов исключений. Его прямым потомком является, например, класс AriphmeticError, имеющий трех потомков - FloatingPointError, OverflowError, ZeroDivisionError. Первый из этих классов в последних версиях Python не используется. Ошибка переполнения возникает, когда результат выполнения арифметических операций над данными с плавающей точкой больше максимально возможного значения.
Чаще всего возникает третье исключение при попытке деления на ноль. Больше всего потомков с разветвленной иерархией имеет класс OSError - прямой потомок класса Exception. Судя по названию, ошибки обнаруживаются при работе операционной системы, в частности, при работе с файлами.
С некоторыми встроенными классами исключений мы уже сталкивались. На прошлой лекции мы видели, что при выполнении оператора утверждений assert возникает исключительная ситуация - AssertionError, когда предикат в утверждении становится ложным. В одной из лекций по ООП при построении класса Rational программно возбуждалось исключение TypeError.
Вы заметили, что имена классов строятся по одному образцу - содержательное имя, заканчивающееся словом Error (ошибка).
Встроенные классы исключений устроены весьма просто. Большинство из них имеет только один аргумент - message - сообщение, которое выдается при возникновении исключения. Некоторые из классов, - большей частью это потомки класса OSError, имеют кортеж аргументов, что позволяет более точно охарактеризовать причину возникновения ситуации. Метод __str__ для объектов таких классов позволяет получить значения аргументов.
Когда строится некоторый класс, задающий тип данных, или сервисный модуль со специфическими сервисами, то, чаще всего, следует параллельно строить класс исключительных ситуаций, описывающий ситуации, которые предположительно могут возникать при некорректной работе с объектами класса или сервисами модуля. Наличие такого класса позволяет должным образом обработать исключительную ситуацию, если она возникнет, что способствует повышению устойчивости программной системы.
Собственный класс исключений должен указать в качестве родителя класс Exception или одного из его потомков, но родителем не может быть класс BaseException.
Имя собственного класса следует задавать согласно общим правилам - быть содержательным и заканчиваться словом Error.
На собственный класс исключений не накладываются какие-либо дополнительные ограничения. Он может быть таким же сложным, как любой класс. Но обычно класс исключений подобен встроенным классам исключений и содержит только один или несколько аргументов, необходимых для идентификации возникшей ошибки. Состав аргументов, конечно, зависит от того класса, для которого строится класс исключительных ситуаций.
Представьте себе, что разрабатывается класс, описывающий некоторую игру человека с компьютером. Ход, сделанный человеком, может оказаться недопустимым в текущей позиции, возбуждая исключительную ситуацию. Класс, описывающий исключительную ситуацию для данной игры, может выглядеть так:
class MoveError(Expression):
"""
Задает исключительную ситуацию,
возникающую в игре, когда в позиции position
выполняется некорректный ход move.
Сообщение message описывает причину некорректности хода.
"""
def __init__(self, position, move, message):
self.position = position
self.move = move
self.message = message
Если в выполняемом фрагменте программы возникла исключительная ситуация и ее обработка не предусмотрена в программе, то работает стандартный обработчик, способный обработать любую возникшую ситуацию. Как он работает? Первым делом ситуация классифицируется, в результате создается объект соответствующего класса. Вычисления по программе прерываются, программа завершает работу с выдачей сообщения о возникшей ситуации. Это сообщение включает трассировку, позволяющую проследить цепочку вызовов методов, приведших к возникновению исключительной ситуации, приводится объект, задающий исключительную ситуацию и сообщение, являющееся атрибутом этого объекта.
С примерами работы стандартного обработчика приходится сталкиваться значительно чаще, чем хотелось бы программисту. Приведу пример из прошлой лекции, когда исключительная ситуация порождалась в результате работы оператора assert:
Трассировка говорит, что исключительная ситуация возникла в модуле Translate.py в строке 84 при вызове метода TranslateFromPtoQ. Вызванный метод находится в том же модуле. При выполнении этого метода в строке 64 оператор assert породил исключительную ситуацию, что привело к созданию объекта класса AssertionError. Сообщение, связанное с объектом, говорит о причине возникновения ситуации.
Стандартный обработчик исключительных ситуаций весьма полезный инструмент. Он позволяет обнаружить ситуацию, классифицировать ее, прервать вычисления, не допуская получения некорректных результатов. Нужно понимать, что лучше не получить результат, чем получить неверный результат и использовать его в дальнейшей работе. Последствия могут быть весьма тяжелыми.
Тем не менее по-настоящему устойчивая программная система должна не только обнаружить ошибку, но постараться по возможности исправить ее и продолжить корректную работу программы. Прерывание вычислений - это крайний случай, когда исправление ошибки не представляется возможным. Давайте посмотрим, какими инструментами располагают программисты при обработке исключительных ситуаций. В Python , как и во многих языках программирования, таким инструментом является охраняемый блок с обработчиками ситуаций - try - except блок (в других языках try - catch блок).
Когда мы создаем некоторый метод, то весь код метода или его фрагмент, допускающий организацию блока, можно оформить в виде try - except блока. Основная конструкция синтаксически это выглядит так:
class pattern(object):
"""образец"""
def method():
<фрагмент кода>
try:
< охраняемый фрагмент кода>
except <имя класса исключений> as <имя объекта>:
< код обработчика исключения>
...
except <имя класса исключений> as <имя объекта>:
< код обработчика исключения>
<фрагмент кода>
Как это работает? При запуске метода method на выполнение возможны следующие сценарии:
Заметьте, начального и заключительного фрагмента кода может не быть, охраняемым может быть весь код метода. Это возможная, но не всегда лучшая стратегия. Охранять нужно то, что действительно требует охраны, те фрагменты кода, где обработка исключения, предусмотренная программистом, дает эффект в сравнении с тем, что дает стандартный обработчик события.
Рассмотрим более подробно, как работают except - обработчики, которых может быть несколько. Их цель - захватить исключение и обработать его. Работают они последовательно в порядке их расположения в тексте. Если обработчику удается захватить исключение, то остальные работать не будут. Обработчик захватывает исключение, если класс объекта исключения совпадает или является потомком класса, указанного в except - обработчике. По этой причине обработчики располагаются в порядке усиления степени универсализации. Вначале располагаются наиболее специализированные обработчики. Последним может располагаться обработчик, задающий класс Exception, - он способен захватить любое исключение. Если ни один из except-обработчиков не захватил исключение, то его захватывает стандартный обработчик, так что исключение всегда будет обработано.
Обработчик, захвативший исключение, выполняет предусмотренный в нем код. При этом он может использовать объект исключение, анализируя атрибуты этого объекта, что полезно при попытке исправить ситуацию и продолжить корректное выполнение.
В языках программирования применяются две схемы обработки исключений - с возобновлением и без возобновления. В первом случае обработчик пытается исправить ситуацию и вернуть управление в try-блок для продолжения корректной работы. В схеме без возобновления обработчик может пытаться исправить ситуацию и сам выполняет ту часть работы, которую не удалось выполнить в try-блоке.
В Python применяется схема без возобновления, но ее можно моделировать, что постараюсь показать в одном из последующих примеров.
Зачастую, except-обработчик Python позволяет выдать более полную информацию об исключительной ситуации в сравнении со стандартным обработчиком. Самое главное, - он может исправить ситуацию обеспечив корректное продолжение работы.
Будьте внимательны! Самая неприятная ошибка, которую часто совершают неопытные программисты, - это выдать в обработчике сообщение об ошибке и продолжить работу с некорректными данными.
Если в доме возник пожар, то мало кричать "пожар" и одновременно предлагать жителям дома спокойно продолжать свои дела. Пожар нужно тушить, жителей нужно спасать.
Давайте рассмотрим вариации синтаксиса в задании except-обработчиков:
except (name1, …name_k). Такой обработчик будет захватывать исключения любого из указанных классов.as может быть опущена, если в процессе обработки не предполагается использовать дополнительные атрибуты объекта исключения помимо атрибута message.Exception.Пришла пора привести пример, демонстрирующий использование охраняемого блока с except-обработчиками исключительных ситуаций:
import random
def f(x):
return x + [1]
def g(x):
return x + 1
def fg():
#начальный блок
x = random.randint(-1, 4)
#охраняемый блок
try:
if x < 1:
y = (x + 1)/ x
elif x > 2:
y = f(x)
else:
y = f([2])
except ZeroDivisionError as e:
print('ошибка: деление на ноль')
print(e)
# Исправление ситуации
print('Исправление ситуации')
x = x + 1
y = (x + 1) / x
except TypeError as e:
print('ошибка: несовместимые типы операндов')
print(e)
# Исправление ситуации
print('Исправление ситуации')
y = g(x)
#финальный блок
print ('финальный результат: y = ', y)
return y
def test1():
print('В охраняемом блоке возможны исключительные ситуации!')
y = fg()
test1()
При запуске теста на выполнение вызывается функция fg(). Эта функция построена в полном соответствии с приведенной выше схемой, - в ней есть начальный, охраняемый и заключительный блоки. В охраняемом блоке в зависимости от значения x, сгенерированного в начальном блоке, по-разному вычисляются значения переменной y. Вычисления могут успешно выполняться, но могут возникать и различные исключительные ситуации. Мы не хотим встраивать дополнительную проверку ситуаций в тело охраняемого блока. Исправление ситуаций возлагается на except-обработчиков, которые в зависимости от возникшей ситуации корректируют данные, чтобы работа функции корректно завершилась.
Конечно, это модельный пример, но он позволяет продемонстрировать все вариации работы охраняемого блока и работу except-обработчиков.
Приведу результаты работы нескольких сеансов работы этого теста, демонстрирующих различные ситуации, возникающие на этих сеансах:
В первом приведенном сеансе в процессе вычислений возникла исключительная ситуация, поскольку была вызвана функция, которой был преданный операнд некорректного типа. Соответствующий обработчик, захвативший исключение TypeError, исправил ситуацию, так что в финальном блоке был получен корректный результат.
Во втором и третьем сеансе работы все обошлось без исключительных ситуаций, - функции вызывались с корректным типом аргумента. В одном случае результатом стал список, в другом - число.
В четвертом сеансе в ходе вычислений возникла ситуация деления на ноль. Обработчик перехватил исключение, исправил ситуацию, и функция завершилась, вернув корректный результат.
Блок try-except может дополняться еще двумя блоками - finally и else.
Блок finally добавляется тогда, когда охраняемый блок захватывает какие-либо ресурсы, чаще всего, файлы, которые требуется освободить, как бы не завершился охраняемый блок - в результате исключений или без них. Если охраняемый блок нормально завершается, то по его окончании выполняется finally блок. Если возникает исключение и его захватил обработчик исключений, то обработчик выполняет свою работу, но, прежде чем завершить работу, выполняет блок finally. Блок finally может следовать за охраняемым блоком даже в случае отсутствия except-обработчиков.
В приведенном выше примере финальный блок работает в двух случаях:
Иногда требуется, чтобы действия, выполняемые в финале, зависели от того, как завершается охраняемый блок - с исключениями или без них. В этом случае в схему после ecept-обработчиков добавляется else-блок, содержащий код, который следует выполнять в случае нормального завершения работы охраняемого блока.
На прошлой лекции мы определяли исключительную ситуацию, как ситуацию, возникающую в процессе выполнения программы, когда корректность программы нарушается. Это правильное определение, но трудно проверяемое на практике. Построение предикатов, использование операторов assert не самый простой способ обнаружения нарушений корректной работы. Чаще всего некорректное поведение программы обнаруживается, когда программа не может выполнить предусмотренную операцию. Примеров масса: не найден в указанном месте затребованный файл, возникла ошибка чтения или записи данных при работе с внешним источником данных, ошибка возникла при попытке деления на ноль или при извлечении квадратного корня из отрицательного числа, при попытке выполнить операцию сложения над операндами, над которыми эта операция не определена. Все эти ситуации являются исключительными, при выполнении любой программы.
В большинстве современных языков программирования появился инструментарий, позволяющий своевременно обнаруживать и должным образом обрабатывать исключительные ситуации, по какой-либо причине они не появились. В Python , как и в других ОО языках программирования, этот инструментарий построен на объектных принципах.
Для программиста исключительная ситуация - это объект, класс которого принадлежит обширному семейству классов, связанных отношением наследования. Эти классы описывают разнообразные исключительные ситуации, которые могут возникать при выполнении программ. Наследование - это прекрасный способ классификации объектов.
Семейство классов, описывающих исключения (Exception), содержит многочисленные встроенные классы и классы, создаваемые программистом. Прародителем всех встроенных классов семейства является класс BaseException, описывающий исключения любого типа. Его потомки - задают специализированные исключения. У этого класса четыре прямых потомка. Три потомка определяют исключения, порожденные устройствами компьютера, например, клавиатурой. Для нас наибольший интерес представляет четвертый потомок - класс Exception. Этот класс является родителем для более чем полусотни встроенных классов исключений. Его прямым потомком является, например, класс AriphmeticError, имеющий трех потомков - FloatingPointError, OverflowError, ZeroDivisionError. Первый из этих классов в последних версиях Python не используется. Ошибка переполнения возникает, когда результат выполнения арифметических операций над данными с плавающей точкой больше максимально возможного значения.
Чаще всего возникает третье исключение при попытке деления на ноль. Больше всего потомков с разветвленной иерархией имеет класс OSError - прямой потомок класса Exception. Судя по названию, ошибки обнаруживаются при работе операционной системы, в частности, при работе с файлами.
С некоторыми встроенными классами исключений мы уже сталкивались. На прошлой лекции мы видели, что при выполнении оператора утверждений assert возникает исключительная ситуация - AssertionError, когда предикат в утверждении становится ложным. В одной из лекций по ООП при построении класса Rational программно возбуждалось исключение TypeError.
Вы заметили, что имена классов строятся по одному образцу - содержательное имя, заканчивающееся словом Error (ошибка).
Встроенные классы исключений устроены весьма просто. Большинство из них имеет только один аргумент - message - сообщение, которое выдается при возникновении исключения. Некоторые из классов, - большей частью это потомки класса OSError, имеют кортеж аргументов, что позволяет более точно охарактеризовать причину возникновения ситуации. Метод __str__ для объектов таких классов позволяет получить значения аргументов.
Когда строится некоторый класс, задающий тип данных, или сервисный модуль со специфическими сервисами, то, чаще всего, следует параллельно строить класс исключительных ситуаций, описывающий ситуации, которые предположительно могут возникать при некорректной работе с объектами класса или сервисами модуля. Наличие такого класса позволяет должным образом обработать исключительную ситуацию, если она возникнет, что способствует повышению устойчивости программной системы.
Собственный класс исключений должен указать в качестве родителя класс Exception или одного из его потомков, но родителем не может быть класс BaseException.
Имя собственного класса следует задавать согласно общим правилам - быть содержательным и заканчиваться словом Error.
На собственный класс исключений не накладываются какие-либо дополнительные ограничения. Он может быть таким же сложным, как любой класс. Но обычно класс исключений подобен встроенным классам исключений и содержит только один или несколько аргументов, необходимых для идентификации возникшей ошибки. Состав аргументов, конечно, зависит от того класса, для которого строится класс исключительных ситуаций.
Представьте себе, что разрабатывается класс, описывающий некоторую игру человека с компьютером. Ход, сделанный человеком, может оказаться недопустимым в текущей позиции, возбуждая исключительную ситуацию. Класс, описывающий исключительную ситуацию для данной игры, может выглядеть так:
class MoveError(Expression):
"""
Задает исключительную ситуацию,
возникающую в игре, когда в позиции position
выполняется некорректный ход move.
Сообщение message описывает причину некорректности хода.
"""
def __init__(self, position, move, message):
self.position = position
self.move = move
self.message = message
Если в выполняемом фрагменте программы возникла исключительная ситуация и ее обработка не предусмотрена в программе, то работает стандартный обработчик, способный обработать любую возникшую ситуацию. Как он работает? Первым делом ситуация классифицируется, в результате создается объект соответствующего класса. Вычисления по программе прерываются, программа завершает работу с выдачей сообщения о возникшей ситуации. Это сообщение включает трассировку, позволяющую проследить цепочку вызовов методов, приведших к возникновению исключительной ситуации, приводится объект, задающий исключительную ситуацию и сообщение, являющееся атрибутом этого объекта.
С примерами работы стандартного обработчика приходится сталкиваться значительно чаще, чем хотелось бы программисту. Приведу пример из прошлой лекции, когда исключительная ситуация порождалась в результате работы оператора assert:
Трассировка говорит, что исключительная ситуация возникла в модуле Translate.py в строке 84 при вызове метода TranslateFromPtoQ. Вызванный метод находится в том же модуле. При выполнении этого метода в строке 64 оператор assert породил исключительную ситуацию, что привело к созданию объекта класса AssertionError. Сообщение, связанное с объектом, говорит о причине возникновения ситуации.
Стандартный обработчик исключительных ситуаций весьма полезный инструмент. Он позволяет обнаружить ситуацию, классифицировать ее, прервать вычисления, не допуская получения некорректных результатов. Нужно понимать, что лучше не получить результат, чем получить неверный результат и использовать его в дальнейшей работе. Последствия могут быть весьма тяжелыми.
Тем не менее по-настоящему устойчивая программная система должна не только обнаружить ошибку, но постараться по возможности исправить ее и продолжить корректную работу программы. Прерывание вычислений - это крайний случай, когда исправление ошибки не представляется возможным. Давайте посмотрим, какими инструментами располагают программисты при обработке исключительных ситуаций. В Python , как и во многих языках программирования, таким инструментом является охраняемый блок с обработчиками ситуаций - try - except блок (в других языках try - catch блок).
Когда мы создаем некоторый метод, то весь код метода или его фрагмент, допускающий организацию блока, можно оформить в виде try - except блока. Основная конструкция синтаксически это выглядит так:
class pattern(object):
"""образец"""
def method():
<фрагмент кода>
try:
< охраняемый фрагмент кода>
except <имя класса исключений> as <имя объекта>:
< код обработчика исключения>
...
except <имя класса исключений> as <имя объекта>:
< код обработчика исключения>
<фрагмент кода>
Как это работает? При запуске метода method на выполнение возможны следующие сценарии:
Заметьте, начального и заключительного фрагмента кода может не быть, охраняемым может быть весь код метода. Это возможная, но не всегда лучшая стратегия. Охранять нужно то, что действительно требует охраны, те фрагменты кода, где обработка исключения, предусмотренная программистом, дает эффект в сравнении с тем, что дает стандартный обработчик события.
Рассмотрим более подробно, как работают except - обработчики, которых может быть несколько. Их цель - захватить исключение и обработать его. Работают они последовательно в порядке их расположения в тексте. Если обработчику удается захватить исключение, то остальные работать не будут. Обработчик захватывает исключение, если класс объекта исключения совпадает или является потомком класса, указанного в except - обработчике. По этой причине обработчики располагаются в порядке усиления степени универсализации. Вначале располагаются наиболее специализированные обработчики. Последним может располагаться обработчик, задающий класс Exception, - он способен захватить любое исключение. Если ни один из except-обработчиков не захватил исключение, то его захватывает стандартный обработчик, так что исключение всегда будет обработано.
Обработчик, захвативший исключение, выполняет предусмотренный в нем код. При этом он может использовать объект исключение, анализируя атрибуты этого объекта, что полезно при попытке исправить ситуацию и продолжить корректное выполнение.
В языках программирования применяются две схемы обработки исключений - с возобновлением и без возобновления. В первом случае обработчик пытается исправить ситуацию и вернуть управление в try-блок для продолжения корректной работы. В схеме без возобновления обработчик может пытаться исправить ситуацию и сам выполняет ту часть работы, которую не удалось выполнить в try-блоке.
В Python применяется схема без возобновления, но ее можно моделировать, что постараюсь показать в одном из последующих примеров.
Зачастую, except-обработчик Python позволяет выдать более полную информацию об исключительной ситуации в сравнении со стандартным обработчиком. Самое главное, - он может исправить ситуацию обеспечив корректное продолжение работы.
Будьте внимательны! Самая неприятная ошибка, которую часто совершают неопытные программисты, - это выдать в обработчике сообщение об ошибке и продолжить работу с некорректными данными.
Если в доме возник пожар, то мало кричать "пожар" и одновременно предлагать жителям дома спокойно продолжать свои дела. Пожар нужно тушить, жителей нужно спасать.
Давайте рассмотрим вариации синтаксиса в задании except-обработчиков:
except (name1, …name_k). Такой обработчик будет захватывать исключения любого из указанных классов.as может быть опущена, если в процессе обработки не предполагается использовать дополнительные атрибуты объекта исключения помимо атрибута message.Exception.Пришла пора привести пример, демонстрирующий использование охраняемого блока с except-обработчиками исключительных ситуаций:
import random
def f(x):
return x + [1]
def g(x):
return x + 1
def fg():
#начальный блок
x = random.randint(-1, 4)
#охраняемый блок
try:
if x < 1:
y = (x + 1)/ x
elif x > 2:
y = f(x)
else:
y = f([2])
except ZeroDivisionError as e:
print('ошибка: деление на ноль')
print(e)
# Исправление ситуации
print('Исправление ситуации')
x = x + 1
y = (x + 1) / x
except TypeError as e:
print('ошибка: несовместимые типы операндов')
print(e)
# Исправление ситуации
print('Исправление ситуации')
y = g(x)
#финальный блок
print ('финальный результат: y = ', y)
return y
def test1():
print('В охраняемом блоке возможны исключительные ситуации!')
y = fg()
test1()
При запуске теста на выполнение вызывается функция fg(). Эта функция построена в полном соответствии с приведенной выше схемой, - в ней есть начальный, охраняемый и заключительный блоки. В охраняемом блоке в зависимости от значения x, сгенерированного в начальном блоке, по-разному вычисляются значения переменной y. Вычисления могут успешно выполняться, но могут возникать и различные исключительные ситуации. Мы не хотим встраивать дополнительную проверку ситуаций в тело охраняемого блока. Исправление ситуаций возлагается на except-обработчиков, которые в зависимости от возникшей ситуации корректируют данные, чтобы работа функции корректно завершилась.
Конечно, это модельный пример, но он позволяет продемонстрировать все вариации работы охраняемого блока и работу except-обработчиков.
Приведу результаты работы нескольких сеансов работы этого теста, демонстрирующих различные ситуации, возникающие на этих сеансах:
В первом приведенном сеансе в процессе вычислений возникла исключительная ситуация, поскольку была вызвана функция, которой был преданный операнд некорректного типа. Соответствующий обработчик, захвативший исключение TypeError, исправил ситуацию, так что в финальном блоке был получен корректный результат.
Во втором и третьем сеансе работы все обошлось без исключительных ситуаций, - функции вызывались с корректным типом аргумента. В одном случае результатом стал список, в другом - число.
В четвертом сеансе в ходе вычислений возникла ситуация деления на ноль. Обработчик перехватил исключение, исправил ситуацию, и функция завершилась, вернув корректный результат.
Блок try-except может дополняться еще двумя блоками - finally и else.
Блок finally добавляется тогда, когда охраняемый блок захватывает какие-либо ресурсы, чаще всего, файлы, которые требуется освободить, как бы не завершился охраняемый блок - в результате исключений или без них. Если охраняемый блок нормально завершается, то по его окончании выполняется finally блок. Если возникает исключение и его захватил обработчик исключений, то обработчик выполняет свою работу, но, прежде чем завершить работу, выполняет блок finally. Блок finally может следовать за охраняемым блоком даже в случае отсутствия except-обработчиков.
В приведенном выше примере финальный блок работает в двух случаях:
Иногда требуется, чтобы действия, выполняемые в финале, зависели от того, как завершается охраняемый блок - с исключениями или без них. В этом случае в схему после ecept-обработчиков добавляется else-блок, содержащий код, который следует выполнять в случае нормального завершения работы охраняемого блока.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.