Когда мы работаем с собственным классом и спроектированным для него классом исключений, то, понятно, исключение может появиться только в результате выполнения кода, написанного программистом. Обнаружить ситуацию, приводящую к некорректной работе класса и его объектов, создать в этом случае объект исключение, передав ему соответствующие аргументы, - все это выполняется обычными программными средствами, ведь исключение это такой же объект, как и другие объекты, с которыми работает программист. Но для того чтобы реально возникла исключительная ситуация, прерывающая выполнение программного кода, необходим в этом случае специальный оператор, который "возбуждает" исключение. Иногда говорят, что оператор "поднимает" или " выбрасывает" исключение. Таким оператором в языке Python является оператор raise. Синтаксис оператора имеет вид:
raise [<expression1> [from <expression2>] ]
Рассмотрим семантику оператора:
raise. Если активного исключения нет, то возбуждается исключение класса RuntimeError.BaseException. В этом случае возбуждается исключение, тип которого определяется заданным классом, а значением соответствующий объект. Если в операторе указан класс, а не объект, то объект создается автоматически конструктором по умолчанию. Для собственных классов исключений, имеющих кортеж аргументов, при возбуждении исключения соответствующий объект следует создать.raise помимо выражения1 указывается и from выражение 2, то это выражение также задает класс исключений или объект исключений. Такое исключение присоединяется к исключению, заданному в выражении1. Эта редко используемая форма применяется обычно в except-обработчиках, когда обработчик в ходе своей работы возбуждает собственное исключение, присоединяя к нему исключение, захваченное обработчиком.Приведу пример, где обработчик исключения захватывает любое исключение. В процессе обработки выбрасывает исключение RuntimeError, присоединяя к нему захваченное исключение:
def ff():
try:
x = 1
y = [2]
z = x + y
except Exception as except_obj:
raise RuntimeError("Серьезная ошибка при выполнении ff") from except_obj
Вот как выглядит информация, выдаваемая при запуске этой функции:
С другими примерами применения оператора raise мы сталкивались в предыдущих лекциях, в частности, при описании методов класса Rational возбуждалось исключение класса TypeError.
Понимание того, как обрабатывается исключительная ситуация, требует более серьезного рассмотрения. До сих пор неявно предполагалось, что исключительная ситуация возбуждается в охраняемом блоке и один из except-обработчиков этого блока выполняет обработку этой ситуации. Однако зачастую в обработке возникшей ситуации участвует ансамбль обработчиков разных охраняемых блоков. Дело в том, что в теле охраняемого блока метода f1 может содержаться вызов метода f2, в свою очередь содержащего охраняемый блок с соответствующими except-обработчиками. Транзитивно ситуация может повторяться. Предположим, что исключительная ситуация возникла в методе fk. Понятно, что возлагать всю ответственность за обработку ситуации только на except-обработчиков блока fk неразумно, - обработчики всех блоков должны принять участие в обработке, главная ответственность лежит на except-обработчиках блока f1 - метода, породившего цепочку вызовов, приведшую к появлению исключительной ситуации.
Как строится обработка исключения в таких случаях? Первым ситуацию пытается исправить except-обработчик того блока, в котором возникла ситуация. Заканчивает он свою работу вызовом оператора raise, возбуждая активную исключительную ситуацию. В результате происходит подъем по цепочке вызовов методов и в исправление ситуации принимает очередной разработчик. На каком-то шаге ситуация может быть исправлена, исключительная ситуация не возбуждается и продолжается нормальное выполнение. Другой исход - завершение работы, когда становится понятно, что дальнейшее продолжение работы становится невозможным. Чаще всего, окончательное решение принимается при обработке ситуации в вызывающем методе f1.
Давайте вернемся к выше приведенному примеру, где подобная ситуация имела место, хотя я не акцентировал на этом внимания. Напомню суть примера. В тесте вызывалась функция fg, в теле которой был охраняемый блок с except-обработчиками. При выполнении этой функции могли возникать исключительные ситуации двух типов. Ситуация деления на ноль возникала непосредственно в охраняемом блоке функции fg и except-обработчик этого блока исправлял ситуацию, продолжая выполнение программы. Вторая же ситуация, связанная с некорректностью типа операнда, возникала при вызове функции f. У этой функции не было охраняемого блока и соответственно except-обработчиков. Поэтому при возникновении исключительной ситуации был вызван стандартный обработчик исключения, который исправить ситуацию не в состоянии, завершить выполнение программы не вправе, он обязан передать управление вышестоящему except-обработчику, что и было сделано. Обработчик охраняемого блока функции fg смог исправить ситуацию и выполнение
программы продолжилось.
Сейчас я построю более сложный пример, проясняющий детали обработки исключения при наличии цепочки вызовов методов в теле охраняемых блоков.
Приведу пример, в котором:
Work и связанный с ним класс ProcessError, описывающий исключительную ситуацию, которая может возникать в процессе работы методов класса Work.Work построены три метода: Begin, Start, Process, каждый из которых содержит охраняемый блок с соответствующим except-обработчиком.Begin =>l Start => Process.Process, выполняется ансамблем обработчиков, подъемом по цепочке вызовов: Begin <= Start <= Process.В этом примере я выполню сделанное ранее обещание показать, как можно в Python моделировать схему обработки исключения с возобновлением, когда управление передается try-блоку для повторного выполнения с надеждой на нормальное продолжение работы, благодаря изменениям, сделанным ансамблем обработчиков. Идея такой схемы состоит в том, что охраняемый блок заключается в цикл. Если при работе охраняемого блока исключительная ситуация не возникает, то цикл завершает работу при однократном выполнении тела цикла. Если же исключительная ситуация возникла, то обработчики ситуации вносят изменения, при которых тело цикла на следующей итерации будет работать по-другому, например. исполнять альтернативный алгоритм, использовать новую эвристику.
Перейду к описанию примера, моделирующего некий производственный процесс. Вот начало описания класса Work:
import random
from ProcessError import ProcessError
class Work(object):
"""
Моделирует производственный процесс
"""
#границы показателя эффективности процесса
Low = -10
Up = 20
res = []
was_exception = True
def __init__(self):
pass
У класса задан ряд атрибутов класса, которые будут использоваться обработчиками события, чтобы повлиять на результаты производственного процесса. Заметьте, я не стал вводить атрибуты, присущих объектам класса.
Давайте теперь определим три взаимосвязанных метода, моделирующих некоторый производственный процесс:
def Begin(self):
print('Подготовка запуска процесса')
while self.was_exception:
self.was_exception = False
try:
self.Start()
except ProcessError as exc:
print('ProcessError:' +
'Обработчик Begin пытается исправить ситуацию.' +
'Повторно запускает процесс')
self.res = []
self.Low += 2
print("Процесс нормальный! ")
print(self.res)
Работа начинается с вызова метода Begin, который вызывает метод Start, продолжающий работу. Заметьте, try-блок обернут в цикл while, условие которого определяется атрибутом класса - was_exception (было ли исключение). Инициализируется этот атрибут значением True, так что первый раз тело цикла будет выполняться. Но уже первый оператор тела цикла меняет это значение на False, так что если в процессе выполнения процесса исключительная ситуация не возникнет, то метод нормально завершит работу, сообщив об этом, и напечатав результат работы - список res. Если же ситуация возникнет, то метод повторно выполнит try-блок, но при этом параметры, управляющие процессом, изменятся в except-обработчиках, способствуя нормализации процесса работы. Гарантируется, что в процессе итераций нормальная работа будет достигнута.
Вот код следующего метода Start:
def Start(self):
print('Запуск процесса')
try:
self.Process()
except ProcessError as exc:
print('ProcessError:' +
'Обработчик Start пытается исправить ситуацию.' +
'Передает управление вышестоящему обработчику')
self.Low += 1
raise
Этот метод вызывает метод Process, непосредственно выполняющий процесс. Его event-обработчик ситуации ProcessError изменяет параметр Low,влияющий на ход процесса и в заключение повторно возбуждает исключение ProcessError, передавая управление обработчику этой ситуации в методе Begin.
Вот код метода Process, выполняющего процесс, приводящий иногда к исключительной ситуации ProcessError, считающейся некорректной:
def Process(self):
s = 'Показатель эффективности процесса ниже нормы'
try:
count = 0
for i in range(0, 10):
p = random.randint(self.Low, self.Up)
self.res.append(p)
if p < 0:
count += 1
if count > 2:
raise ProcessError(s, self.Low, self.res)
self.was_exception = False
return self.res
except ProcessError as exc:
print('ProcessError:' +
'Обработчик Process пытается исправить ситуацию.' +
'Передает управление вышестояшему обработчику')
self.was_exception = True;
self.Low += 1
raise
Производственный процесс моделируется тем, что заполняется список случайными числами. Среди 10 чисел этого списка отрицательных должно быть меньше заданной константы, иначе возникает исключительная ситуация, считается что процесс некорректен. Если исключительная ситуация возникла, то параметр was-exception принимает значение True,что приведет к повторению запуска процесса. Одновременно параметр Low увеличивается, что приводит к уменьшению вероятности появления отрицательных чисел. По завершении обработки исключения управление передается вышестоящему обработчику.
Так устроен класс Work. Посмотрим теперь, как устроен класс ProcessError, определяющий исключительную ситуацию:
class ProcessError(Exception):
"""
Класс исключений для класса Work
"""
def __init__(self, message, limit, result):
self.message = message
self.limit = limit
self.result = result
Как обычно, для класса задан только конструктор, позволяющий в процессе обработки использовать атрибуты объекта исключения. В примере я не использовал эту возможность, ограничившись только выводом информации, передаваемой этому объекту.
Для полноты картины приведу тест, запускающий выполнение построенной модели:
def test3():
from Work import Work
work = Work()
work.Begin()
Приведу теперь результаты работы этого теста для двух сеансов работы:
В первом сеансе исключительная ситуация не возникла и процесс завершился нормально. В результирующем списке два отрицательных элемента, что считается допустимым для нормального процесса. Во втором сеансе при первом запуске выполнение было прервано, поскольку были получены три отрицательных результата, что отражено в параметрах объекта-исключение. Обработчики ситуации подправили параметры процесса и повторный запуск завершился нормально.
Когда мы работаем с собственным классом и спроектированным для него классом исключений, то, понятно, исключение может появиться только в результате выполнения кода, написанного программистом. Обнаружить ситуацию, приводящую к некорректной работе класса и его объектов, создать в этом случае объект исключение, передав ему соответствующие аргументы, - все это выполняется обычными программными средствами, ведь исключение это такой же объект, как и другие объекты, с которыми работает программист. Но для того чтобы реально возникла исключительная ситуация, прерывающая выполнение программного кода, необходим в этом случае специальный оператор, который "возбуждает" исключение. Иногда говорят, что оператор "поднимает" или " выбрасывает" исключение. Таким оператором в языке Python является оператор raise. Синтаксис оператора имеет вид:
raise [<expression1> [from <expression2>] ]
Рассмотрим семантику оператора:
raise. Если активного исключения нет, то возбуждается исключение класса RuntimeError.BaseException. В этом случае возбуждается исключение, тип которого определяется заданным классом, а значением соответствующий объект. Если в операторе указан класс, а не объект, то объект создается автоматически конструктором по умолчанию. Для собственных классов исключений, имеющих кортеж аргументов, при возбуждении исключения соответствующий объект следует создать.raise помимо выражения1 указывается и from выражение 2, то это выражение также задает класс исключений или объект исключений. Такое исключение присоединяется к исключению, заданному в выражении1. Эта редко используемая форма применяется обычно в except-обработчиках, когда обработчик в ходе своей работы возбуждает собственное исключение, присоединяя к нему исключение, захваченное обработчиком.Приведу пример, где обработчик исключения захватывает любое исключение. В процессе обработки выбрасывает исключение RuntimeError, присоединяя к нему захваченное исключение:
def ff():
try:
x = 1
y = [2]
z = x + y
except Exception as except_obj:
raise RuntimeError("Серьезная ошибка при выполнении ff") from except_obj
Вот как выглядит информация, выдаваемая при запуске этой функции:
С другими примерами применения оператора raise мы сталкивались в предыдущих лекциях, в частности, при описании методов класса Rational возбуждалось исключение класса TypeError.
Понимание того, как обрабатывается исключительная ситуация, требует более серьезного рассмотрения. До сих пор неявно предполагалось, что исключительная ситуация возбуждается в охраняемом блоке и один из except-обработчиков этого блока выполняет обработку этой ситуации. Однако зачастую в обработке возникшей ситуации участвует ансамбль обработчиков разных охраняемых блоков. Дело в том, что в теле охраняемого блока метода f1 может содержаться вызов метода f2, в свою очередь содержащего охраняемый блок с соответствующими except-обработчиками. Транзитивно ситуация может повторяться. Предположим, что исключительная ситуация возникла в методе fk. Понятно, что возлагать всю ответственность за обработку ситуации только на except-обработчиков блока fk неразумно, - обработчики всех блоков должны принять участие в обработке, главная ответственность лежит на except-обработчиках блока f1 - метода, породившего цепочку вызовов, приведшую к появлению исключительной ситуации.
Как строится обработка исключения в таких случаях? Первым ситуацию пытается исправить except-обработчик того блока, в котором возникла ситуация. Заканчивает он свою работу вызовом оператора raise, возбуждая активную исключительную ситуацию. В результате происходит подъем по цепочке вызовов методов и в исправление ситуации принимает очередной разработчик. На каком-то шаге ситуация может быть исправлена, исключительная ситуация не возбуждается и продолжается нормальное выполнение. Другой исход - завершение работы, когда становится понятно, что дальнейшее продолжение работы становится невозможным. Чаще всего, окончательное решение принимается при обработке ситуации в вызывающем методе f1.
Давайте вернемся к выше приведенному примеру, где подобная ситуация имела место, хотя я не акцентировал на этом внимания. Напомню суть примера. В тесте вызывалась функция fg, в теле которой был охраняемый блок с except-обработчиками. При выполнении этой функции могли возникать исключительные ситуации двух типов. Ситуация деления на ноль возникала непосредственно в охраняемом блоке функции fg и except-обработчик этого блока исправлял ситуацию, продолжая выполнение программы. Вторая же ситуация, связанная с некорректностью типа операнда, возникала при вызове функции f. У этой функции не было охраняемого блока и соответственно except-обработчиков. Поэтому при возникновении исключительной ситуации был вызван стандартный обработчик исключения, который исправить ситуацию не в состоянии, завершить выполнение программы не вправе, он обязан передать управление вышестоящему except-обработчику, что и было сделано. Обработчик охраняемого блока функции fg смог исправить ситуацию и выполнение
программы продолжилось.
Сейчас я построю более сложный пример, проясняющий детали обработки исключения при наличии цепочки вызовов методов в теле охраняемых блоков.
Приведу пример, в котором:
Work и связанный с ним класс ProcessError, описывающий исключительную ситуацию, которая может возникать в процессе работы методов класса Work.Work построены три метода: Begin, Start, Process, каждый из которых содержит охраняемый блок с соответствующим except-обработчиком.Begin =>l Start => Process.Process, выполняется ансамблем обработчиков, подъемом по цепочке вызовов: Begin <= Start <= Process.В этом примере я выполню сделанное ранее обещание показать, как можно в Python моделировать схему обработки исключения с возобновлением, когда управление передается try-блоку для повторного выполнения с надеждой на нормальное продолжение работы, благодаря изменениям, сделанным ансамблем обработчиков. Идея такой схемы состоит в том, что охраняемый блок заключается в цикл. Если при работе охраняемого блока исключительная ситуация не возникает, то цикл завершает работу при однократном выполнении тела цикла. Если же исключительная ситуация возникла, то обработчики ситуации вносят изменения, при которых тело цикла на следующей итерации будет работать по-другому, например. исполнять альтернативный алгоритм, использовать новую эвристику.
Перейду к описанию примера, моделирующего некий производственный процесс. Вот начало описания класса Work:
import random
from ProcessError import ProcessError
class Work(object):
"""
Моделирует производственный процесс
"""
#границы показателя эффективности процесса
Low = -10
Up = 20
res = []
was_exception = True
def __init__(self):
pass
У класса задан ряд атрибутов класса, которые будут использоваться обработчиками события, чтобы повлиять на результаты производственного процесса. Заметьте, я не стал вводить атрибуты, присущих объектам класса.
Давайте теперь определим три взаимосвязанных метода, моделирующих некоторый производственный процесс:
def Begin(self):
print('Подготовка запуска процесса')
while self.was_exception:
self.was_exception = False
try:
self.Start()
except ProcessError as exc:
print('ProcessError:' +
'Обработчик Begin пытается исправить ситуацию.' +
'Повторно запускает процесс')
self.res = []
self.Low += 2
print("Процесс нормальный! ")
print(self.res)
Работа начинается с вызова метода Begin, который вызывает метод Start, продолжающий работу. Заметьте, try-блок обернут в цикл while, условие которого определяется атрибутом класса - was_exception (было ли исключение). Инициализируется этот атрибут значением True, так что первый раз тело цикла будет выполняться. Но уже первый оператор тела цикла меняет это значение на False, так что если в процессе выполнения процесса исключительная ситуация не возникнет, то метод нормально завершит работу, сообщив об этом, и напечатав результат работы - список res. Если же ситуация возникнет, то метод повторно выполнит try-блок, но при этом параметры, управляющие процессом, изменятся в except-обработчиках, способствуя нормализации процесса работы. Гарантируется, что в процессе итераций нормальная работа будет достигнута.
Вот код следующего метода Start:
def Start(self):
print('Запуск процесса')
try:
self.Process()
except ProcessError as exc:
print('ProcessError:' +
'Обработчик Start пытается исправить ситуацию.' +
'Передает управление вышестоящему обработчику')
self.Low += 1
raise
Этот метод вызывает метод Process, непосредственно выполняющий процесс. Его event-обработчик ситуации ProcessError изменяет параметр Low,влияющий на ход процесса и в заключение повторно возбуждает исключение ProcessError, передавая управление обработчику этой ситуации в методе Begin.
Вот код метода Process, выполняющего процесс, приводящий иногда к исключительной ситуации ProcessError, считающейся некорректной:
def Process(self):
s = 'Показатель эффективности процесса ниже нормы'
try:
count = 0
for i in range(0, 10):
p = random.randint(self.Low, self.Up)
self.res.append(p)
if p < 0:
count += 1
if count > 2:
raise ProcessError(s, self.Low, self.res)
self.was_exception = False
return self.res
except ProcessError as exc:
print('ProcessError:' +
'Обработчик Process пытается исправить ситуацию.' +
'Передает управление вышестояшему обработчику')
self.was_exception = True;
self.Low += 1
raise
Производственный процесс моделируется тем, что заполняется список случайными числами. Среди 10 чисел этого списка отрицательных должно быть меньше заданной константы, иначе возникает исключительная ситуация, считается что процесс некорректен. Если исключительная ситуация возникла, то параметр was-exception принимает значение True,что приведет к повторению запуска процесса. Одновременно параметр Low увеличивается, что приводит к уменьшению вероятности появления отрицательных чисел. По завершении обработки исключения управление передается вышестоящему обработчику.
Так устроен класс Work. Посмотрим теперь, как устроен класс ProcessError, определяющий исключительную ситуацию:
class ProcessError(Exception):
"""
Класс исключений для класса Work
"""
def __init__(self, message, limit, result):
self.message = message
self.limit = limit
self.result = result
Как обычно, для класса задан только конструктор, позволяющий в процессе обработки использовать атрибуты объекта исключения. В примере я не использовал эту возможность, ограничившись только выводом информации, передаваемой этому объекту.
Для полноты картины приведу тест, запускающий выполнение построенной модели:
def test3():
from Work import Work
work = Work()
work.Begin()
Приведу теперь результаты работы этого теста для двух сеансов работы:
В первом сеансе исключительная ситуация не возникла и процесс завершился нормально. В результирующем списке два отрицательных элемента, что считается допустимым для нормального процесса. Во втором сеансе при первом запуске выполнение было прервано, поскольку были получены три отрицательных результата, что отражено в параметрах объекта-исключение. Обработчики ситуации подправили параметры процесса и повторный запуск завершился нормально.
Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.