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

  • Структура программы и ее выполнение

  • Встроенные типы исключений

  • Исключение Описание

  • Определение новых исключений

  • Менеджеры контекста и инструкция with

  • Отладочные проверки и переменная __debug__

  • справочник по Python. мм isbn 9785932861578 9 785932 861578


    Скачать 4.21 Mb.
    Названиемм isbn 9785932861578 9 785932 861578
    Анкорсправочник по Python
    Дата08.05.2022
    Размер4.21 Mb.
    Формат файлаpdf
    Имя файлаBizli_Python-Podrobnyy-spravochnik.440222.pdf
    ТипСправочник
    #518195
    страница10 из 82
    1   ...   6   7   8   9   10   11   12   13   ...   82
    Глава
    5
    .
    Структура программы
    и управление потоком выполнения
    В этой главе подробно рассматриваются структура программы и способы управления потоком выполнения. В число рассматриваемых тем входят: условные операторы, итерации, исключения и менеджеры контекста.
    Структура программы и ее выполнение
    Программы на языке Python представляют собой последовательности ин-
    Python представляют собой последовательности ин- представляют собой последовательности ин- струкций. Все функциональные возможности языка, включая присваива- ние значений переменным, определение функций и классов, импортирова- ние модулей, реализованы в виде инструкций, обладающих равным поло- жением со всеми остальными инструкциями. В действительности в языке
    Python нет «специальных» инструкций и всякая инструкция может быть помещена в любом месте в программе. Например, в следующем фрагменте определяются две различные версии функции:
    if debug:
    def square(x):
    if not isinstance(x,float):
    raise TypeError(“Expected a float”)
    return x * x else:
    def square(x):
    return x * x
    Загружая исходные файлы программы, интерпретатор всегда последова- тельно выполняет все инструкции, пока не встретит конец файла. Эта мо- дель выполнения в равной степени относится как к главному файлу про- граммы, так и к библиотечным файлам модулей, загружаемым с помощью инструкции import.

    Выполнение по условию
    117
    Выполнение по условию
    Инструкции if, else и elif позволяют организовать выполнение программ- ного кода в зависимости от условий. В общем случае условная инструкция имеет следующий вид:
    if
    выражение:
    инструкции
    elif
    выражение:
    инструкции
    elif
    выражение:
    инструкции
    ...
    else:
    инструкции
    Если при несоблюдении условия никаких действий не должно выполнять- ся, можно опустить части else и elif условной инструкции. Если действия не должны выполняться при соблюдении определенного условия, можно использовать инструкцию pass:
    if
    выражение:
    pass # Ничего не делает else:
    инструкции
    Циклы и итерации
    Циклы в языке Python оформляются с помощью инструкций for и while.
    Например:
    while
    выражение:
    инструкции
    ёё
    for i in s:
    инструкции
    Инструкция while выполняет инструкции, пока условное выражение не вернет значение False. Инструкция for выполняет итерации по всем эле- ментам s, пока не исчерпаются доступные элементы. Инструкция for мо- жет работать с любыми объектами, поддерживающими итерации. К числу этих объектов относятся встроенные типы последовательностей, такие как списки, кортежи и строки, а также любые другие объекты, реализующие протокол итераторов.
    Считается, что объект s поддерживает итерации, если он может исполь- зоваться в следующем программном коде, который является отражением реализации инструкции for:
    it = s.__iter__() # Получить итератор для объекта s while 1:
    try:
    i = it.next() # Получить следующий элемент (__next__ в Python 3)
    except StopIteration: # Нет больше элементов

    118
    Глава 5. Структура программы и управление потоком выполнения break
    # Выполнить операции над i
    ...
    Переменная i в инструкции for i in s называется переменной цикла. На каждой итерации она принимает новое значение из объекта s. Область ви- димости переменной цикла не ограничивается инструкцией for. Если перед инструкцией for была объявлена переменная с тем же именем, ее предыду- щее значение будет затерто. Более того, по окончании цикла эта перемен- ная будет хранить последнее значение, полученное в цикле.
    Если элементы, извлекаемые в процессе итерации, являются последова- тельностями одного и того же размера, их можно распаковать в несколько переменных цикла, используя прием, демонстрируемый ниже:
    for x,y,z in s:
    инструкции
    В этом примере объект s должен содержать или воспроизводить последо- вательности, каждая из которых содержит по три элемента. В каждой ите- рации переменным x, y и z будут присваиваться значения элементов соот- ветствующей последовательности. Несмотря на то что наиболее часто этот прием используется, когда объект s является последовательностью корте- жей, тем не менее он может применяться к элементам объекта s, являю- щимся последовательностями любого типа, включая списки, генераторы и строки.
    При выполнении итераций, помимо самих данных, иногда бывает удобно иметь доступ к порядковому номеру итерации, как показано ниже:
    i = 0
    for x in s:
    инструкции
    i += 1
    Для этих целей в языке Python может использоваться встроенная функция enumerate()
    , например:
    for i,x in enumerate(s):
    инструкции
    Вызов enumerate(s) создает итератор, который просто возвращает последо- вательность кортежей (0, s[0]), (1, s[1]), (2, s[2]) и так далее.
    Другая типичная проблема, связанная с организацией циклов, – парал- лельная обработка двух или более последовательностей. Например, цикл, в каждой итерации которого требуется одновременно извлекать элементы из разных последовательностей, может быть реализован так:
    # s и t – это две последовательности i = 0
    while i < len(s) and i < len(t):
    x = s[i] # Извлечь элемент из последовательности s y = t[i] # Извлечь элемент из последовательности t
    инструкции
    i += 1

    Циклы и итерации
    119
    Э
    ту реализацию можно упростить, если воспользоваться функцией zip().
    Например:
    # s и t – это две последовательности for x,y in zip(s,t):
    инструкции
    Функция zip(s,t) объединит последовательности s и t в последовательность кортежей (s[0],t[0]), (s[1],t[1]), (s[2], t[2]) и так далее, остановившись по- сле исчерпания элементов в самой короткой из последовательностей, если их длины не равны. Следует особо отметить, что в версии Python 2 функция zip()
    извлекает все элементы из последовательностей s и t и создает список кортежей. Для генераторов и последовательностей, содержащих огромные количества элементов, такое поведение может оказаться нежелательным.
    Эту проблему можно решить с помощью функции itertools.izip(), которая достигает того же эффекта, что и функция zip(), но вместо того чтобы соз- давать огромный список кортежей, она воспроизводит по одному комплек- ту объединенных значений при каждом обращении. В Python 3 функция zip()
    реализована точно так же.
    Прервать цикл можно с помощью инструкции break. Например, в следую- щем фрагменте выполняется чтение строк из текстового файла, пока не бу- дет встречена пустая строка:
    for line in open(“foo.txt”):
    stripped = line.strip()
    if not stripped:
    break # Пустая строка, прервать чтение
    # Обработать строку stripped
    ...
    Перейти к следующей итерации (пропустив оставшиеся инструкции в теле цикла) можно с помощью инструкции continue. Эта инструкция использу- ется не часто, но иногда она может быть полезна, – когда оформление еще одного уровня вложенности программного кода в условной инструкции могло бы привести к нежелательному усложнению программы. Например, следующий цикл пропускает все пустые строки в файле:
    for line in open(“foo.txt”):
    stripped = line.strip()
    if not stripped:
    continue # Пропустить пустую строку
    # Обработать строку stripped
    ...
    Инструкции break и continue воздействуют только на самый внутренний цикл. Если необходимо организовать выход из глубоко вложенной иерар- хии циклов, можно воспользоваться исключением. В языке Python отсут-
    Python отсут- отсут- ствует инструкция «goto».
    К инструкции цикла можно также присоединить инструкцию else, как по- казано в следующем примере:
    # for-else for line in open(“foo.txt”):

    120
    Глава 5. Структура программы и управление потоком выполнения stripped = line.strip()
    if not stripped:
    break
    # Обработать строку stripped
    ...
    else:
    raise RuntimeError(“Отсутствует разделитель параграфов”)
    Б
    лок else в инструкции цикла выполняется только в случае нормального завершения цикла, то есть либо когда не было выполнено ни одной итера- ции, либо после выполнения последней итерации. Если выполнение цикла прерывается преждевременно с помощью инструкции break, блок else про- пускается.
    Основное назначение инструкции else в циклах заключается в том, чтобы избежать установки или проверки какого-либо флага или условия, когда работа цикла прерывается преждевременно. Например, предыдущий при- мер можно переписать без использования блока else, но с применением до- полнительной переменной:
    found_separator = False for line in open(“foo.txt”):
    stripped = line.strip()
    if not stripped:
    found_separator = True break
    # Обработать строку stripped
    ...
    ёё
    if not found_separator:
    raise RuntimeError(“Отсутствует разделитель параграфов “)
    Исключения
    Исключения
    свидетельствуют об ошибках и прерывают нормальный ход выполнения программы. Исключения возбуждаются с помощью инструк- ции raise. В общем случае инструкция raise имеет следующий вид: raise
    Exception([value])
    , где Exception – тип исключения, а value – необязательное значение с дополнительной информацией об исключении. Например:
    raise RuntimeError(“Неустранимая ошибка”)
    Если инструкция raise используется без дополнительных параметров, она повторно возбуждает последнее исключение (однако такой прием работает только в процессе обработки возникшего исключения).
    Перехватить исключение можно с помощью инструкций try и except, как показано ниже:
    try:
    f = open(‘foo’)
    except IOError as e:
    инструкции

    Исключения
    121
    Когда возникает исключение, интерпретатор прекращает выполнение инструкций в блоке try и отыскивает блок except, соответствующий типу возникшего исключения. В случае успеха управление передается первой инструкции в найденном блоке except. После выполнения блока except вы- полнение программы продолжается с первой инструкции, следующей за блоком try-except. В противном случае исключение передается блоку про- граммного кода, вмещающему инструкцию try. Этот программный код в свою очередь также может быть заключен в блок try-except, предусматри- вающий обработку исключения. Если исключение достигнет самого верх- него уровня программы и не будет перехвачено, интерпретатор прервет выполнение программы с сообщением об ошибке. При необходимости все неперехваченные исключения можно обработать в пользовательской функ- ции sys.excepthook(), как описывается в главе 13 «Службы Python времени выполнения».
    Необязательный модификатор as var в инструкции except определяет имя переменной, в которую будет записан тип возникшего исключения. Обра- ботчики исключений могут использовать это значение для получения более подробной информации об исключении. Например, проверку типа возник- шего исключения можно выполнить с помощью инструкции isinstance().
    Следует отметить, что в предыдущих версиях Python инструкция except записывалась как except ExcType, var, где тип исключения и имя перемен- ной отделялись запятой (,). Этот синтаксис можно (но не рекомендуется) использовать в версии Python 2.6. В новых программах следует использо-
    Python 2.6. В новых программах следует использо-
    2.6. В новых программах следует использо- вать синтаксис as var, потому что он является единственно допустимым в Python 3.
    Допускается использовать несколько блоков except для обработки разных типов исключений, как показано в следующем примере:
    try:
    выполнить некоторые действия except IOError as e:
    # Обработка ошибки ввода-вывода
    ...
    except TypeError as e:
    # Обработка ошибки типа объекта
    ...
    except NameError as e:
    # Обработка ошибки обращения к несуществующему имени
    ...
    Несколько типов исключений можно также обрабатывать с помощью един- ственного обработчика, например:
    try:
    выполнить некоторые действия except (IOError, TypeError, NameError) as e:
    # Обработать ошибку ввода-вывода, типа
    # или обращения к несуществующему имени
    ...

    122
    Глава 5. Структура программы и управление потоком выполнения
    Игнорировать исключение можно с помощью инструкции pass, как пока- зано ниже:
    try:
    выполнить некоторые действия except IOError:
    pass # Ничего не делать (сойдет и так).
    Перехватить все исключения, кроме тех, что приводят к немедленному за- вершению программы, можно, указав тип исключения Exception, как по- казано ниже:
    try:
    выполнить некоторые действия except Exception as e:
    error_log.write(‘Возникла ошибка: %s\n’ % e)
    Когда перехватываются все типы исключений, необходимо позаботиться о записи в журнал точной информации об ошибке для последующего ана- лиза. Например, в предыдущем фрагменте в журнал записывается инфор- мация, имеющая отношение к исключению. Если пренебречь этой инфор- мацией, будет очень сложно отладить программу, в которой возникают ошибки, появления которых вы не ожидаете.
    С помощью инструкции except, без указания типа исключения, можно пе- рехватывать исключения любых типов:
    try:
    выполнить некоторые действия except:
    error_log.write(‘Ошибка\n’)
    Правильное использование этой формы инструкции except является на- много более сложным делом, чем может показаться, поэтому лучше избе- гать такого способа обработки исключений. Например, этот фрагмент будет также перехватывать прерывания от клавиатуры и запросы на завершение программы, которые едва ли имеет смысл перехватывать.
    Кроме того, инструкция try может сопровождаться блоком else, который должно следовать за последним блоком except. Этот блок выполняется, если в теле инструкции try не возникло исключений. Например:
    try:
    f = open(‘foo’, ‘r’)
    except IOError as e:
    error_log.write(‘Невозможно открыть файл foo: %s\n’ % e)
    else:
    data = f.read()
    f.close()
    Инструкция finally служит для реализации завершающих действий, со- путствующих операциям, выполняемым в блоке try. Например:
    f = open(‘foo’,’r’)
    try:
    # Выполнить некоторые действия

    Исключения
    123
    ...
    finally:
    f.close()
    # Файл будет закрыт, независимо от того, что произойдет
    Б
    лок finally не используется для обработки ошибок. Он используется для реализации действий, которые должны выполняться всегда, независимо от того, возникла ошибка или нет. Если в блоке try исключений не возник- ло, блок finally будет выполнен сразу же вcлед за ним. Если возникло ис- cлед за ним. Если возникло ис- лед за ним. Если возникло ис- ключение, управление сначала будет передано первой инструкции в блоке finally
    , а затем это исключение будет возбуждено повторно, чтобы обеспе- чить возможность его обработки в другом обработчике.
    Встроенные типы исключений
    В табл. 5.1 перечислены встроенные типы исключений, которые определе- табл. 5.1 перечислены встроенные типы исключений, которые определе- табл. 5.1 перечислены встроенные типы исключений, которые определе-
    . 5.1 перечислены встроенные типы исключений, которые определе-
    5.1 перечислены встроенные типы исключений, которые определе- ны в языке Python.
    Таблица 5.1. Встроенные типы исключений
    Исключение
    Описание
    BaseException
    Базовый класс всех исключений
    GeneratorExit
    Возбуждается методом .close() генераторов
    KeyboardInterrupt
    Возбуждается нажатием клавишей прерывания
    (обычно Ctrl-C)
    SystemExit
    Завершение программы
    Exception
    Базовый класс для всех исключений, не связан- ных с завершением программы
    StopIteration
    Возбуждается для прекращения итераций
    StandardError
    Базовый класс для всех встроенных исключе- ний (только в Python 2). В Python 3 – базовый класс всех исключений, наследующих класс
    Exception
    ArithmeticError
    Базовый класс исключений, возбуждаемых арифметическими операциями
    FloatingPointError
    Ошибка операции с плавающей точкой
    ZeroDivisionError
    Деление или деления по модулю на ноль
    AssertionError
    Возбуждается инструкциями assert
    AttributeError
    Возбуждается при обращении к несуществую- щему атрибуту
    EnvironmentError
    Ошибка, обусловленная внешними причинами
    IOError
    Ошибка ввода-вывода при работе с файлами
    OSError
    Ошибка операционной системы
    EOFError
    Возбуждается по достижении конца файла

    124
    Глава 5. Структура программы и управление потоком выполнения
    Исключение
    Описание
    ImportError
    Ошибка в инструкции import
    LookupError
    Ошибка обращения по индексу или ключу
    IndexError
    Ошибка обращения по индексу за пределами последовательности
    KeyError
    Ошибка обращения к несуществующему ключу словаря
    MemoryError
    Нехватка памяти
    NameError
    Не удалось отыскать локальное или глобальное имя
    UnboundLocalError
    Ошибка обращения к локальной переменной, которой еще не было присвоено значение
    ReferenceError
    Ошибка обращения к объекту, который уже был уничтожен
    RuntimeError
    Универсальное исключение
    NotImplementedError
    Обращение к нереализованному методу или функции
    SyntaxError
    Синтаксическая ошибка
    IndentationError
    Ошибка оформления отступов
    TabError
    Непоследовательное использование символа табуляции (генерируется при запуске интерпре- татора с ключом –tt)
    SystemError
    Нефатальная системная ошибка в интерпрета- торе
    TypeError
    Попытка выполнить операцию над аргументом недопустимого типа
    ValueError
    Недопустимый тип
    UnicodeError
    Ошибка при работе с символами Юникода
    UnicodeDecodeError
    Ошибка декодирования символов Юникода
    UnicodeEncodeError
    Ошибка кодирования символов Юникода
    UnicodeTranslateError
    Ошибка трансляции символов Юникода
    Исключения организованы в иерархию, как показано в табл. 5.1. Все ис- ключения, входящие в ту или иную группу, могут быть перехвачены при использовании имени группы в определении блока except. Например:
    try:
    инструкции
    except LookupError: # Перехватит исключение IndexError или KeyError
    инструкции
    Таблица 5.1 (продолжение)

    Исключения
    125
    или try:
    инструкции
    except Exception: # Перехватит любые программные исключения
    инструкции
    Наверху иерархии исключения сгруппированы в зависимости от того, свя- заны ли они с завершением программы. Например, исключения SystemExit и KeyboardInterrupt не входят в группу Exception, потому что, когда програм- мист предусматривает обработку всех программных исключений, он обыч- но не стремится перехватить завершение программы.
    Определение новых исключений
    Все встроенные исключения определяются как классы. Чтобы создать ис- ключение нового типа, нужно объявить новый класс, наследующий класс
    Exception
    , как показано ниже:
    class NetworkError(Exception): pass
    Чтобы воспользоваться новым исключением, его достаточно просто пере- дать инструкции raise, например:
    raise NetworkError(“Невозможно найти компьютер в сети.”)
    При возбуждении исключения с помощью инструкции raise допускается передавать конструктору класса дополнительные значения. В большинстве случаев это обычная строка, содержащая текст сообщения об ошибке. Од- нако пользовательские исключения могут предусматривать возможность приема одного или более значений, как показано в следующем примере:
    class DeviceError(Exception):
    def __init__(self,errno,msg):
    self.args = (errno, msg)
    self.errno = errno self.errmsg = msg
    ёё
    # Возбудить исключение (передав несколько аргументов)
    raise DeviceError(1, ‘Нет ответа’)
    При создании собственного класса исключения, переопределяющего метод
    __init__()
    , важно не забыть присвоить кортеж, содержащий аргументы ме- тода __init__(), атрибуту self.args, как было показано выше. Этот атрибут используется при выводе трассировочной информации. Если оставить этот атрибут пустым, пользователи не смогут увидеть информацию об исключе- нии, когда возникнет ошибка.
    Исключения могут быть организованы в иерархии с помощью механизма наследования. Например, исключение NetworkError, объявленное выше, могло бы служить базовым классом для более специфичных исключений.
    Например:
    class HostnameError(NetworkError): pass class TimeoutError(NetworkError): pass
    ёё

    126
    Глава 5. Структура программы и управление потоком выполнения def error1():
    raise HostnameError(“Хост не найден”)
    ёё
    def error2():
    raise TimeoutError(“Превышено время ожидания”)
    try:
    error1()
    except NetworkError as e:
    if type(e) is HostnameError:
    # Выполнить действия, характерные для ошибки этого типа
    ...
    В данном случае инструкция except NetworkError перехватывает все исклю- чения, наследующие класс NetworkError. Чтобы определить конкретный тип возникшей ошибки, выполняется проверка типа исключения с помо- щью функции type(). Для получения информации о последнем возникшем исключении можно также использовать функцию sys.exc_info().
    Менеджеры контекста и инструкция with
    Надлежащее управление системными ресурсами, такими как файлы, бло- кировки и соединения, часто является достаточно сложной задачей, осо- бенно в соединении с обработкой исключений. Например, возникшее ис- ключение может заставить программу пропустить инструкции, отвечаю- щие за освобождение критических ресурсов, таких как блокировки.
    Инструкция with позволяет организовать выполнение последовательности инструкций внутри контекста, управляемого объектом, который играет роль менеджера контекста. Например:
    with open(“debuglog”,”a”) as f:
    f.write(“Отладка\n”)
    инструкции
    f.write(“Конец\n”)
    ёё
    import threading lock = threading.Lock()
    with lock:
    # Начало критического блока
    инструкции
    # Конец критического блока
    В первом примере инструкция with автоматически закроет открытый файл, когда поток управления покинет блок инструкций, следующий ниже. Во втором примере инструкция with автоматически захватит блокировку, ког- да поток управления войдет в блок инструкций, следующий ниже, и осво- бодит ее при выходе.
    Инструкция with obj позволяет объекту obj управлять происходящим, когда поток управления входит и покидает блок инструкций, следующий ниже. Когда интерпретатор встречает инструкцию with obj, он вызывает метод obj.__enter__(), чтобы известить объект о том, что был выполнен вход в новый контекст. Когда поток управления покидает контекст, вызывается метод obj.__exit__(type,value,traceback). Если при выполнении инструкций

    Менеджеры контекста и инструкция with
    127
    в блоке не возникло никаких исключений, во всех трех аргументах мето- ду __exit__() передается значение None. В противном случае в них записы- ваются тип исключения, его значение и трассировочная информация об исключении, вынудившем поток управления покинуть контекст. Метод
    __exit__()
    возвращает True или False, чтобы показать, было обработано ис- ключение или нет (если возвращается значение False, возникшее исключе- ние продолжит свое движение вверх за пределами контекста).
    Инструкция with obj может принимать дополнительный спецификатор as
    var
    . В этом случае значение, возвращаемое методом obj.__enter__(), записы- вается в переменную var. Важно отметить, что в переменную var не обяза- тельно будет записано значение obj.
    Инструкция with способна работать только с объектами, поддерживаю- щими протокол управления контекстом (методы __enter__() и __exit__()).
    Пользовательские классы также могут определять эти методы, чтобы реа- лизовать собственный способ управления контекстом. Ниже приводится простой пример такого класса:
    class ListTransaction(object):
    def __init__(self,thelist):
    self.thelist = thelist def __enter__(self):
    self.workingcopy = list(self.thelist)
    return self.workingcopy def __exit__(self,type,value,tb):
    if type is None:
    self.thelist[:] = self.workingcopy return False
    Этот класс позволяет выполнять серию модификаций в существующем списке. При этом модификации вступят в силу, только если в процессе их выполнения не возникло исключения. В противном случае список останет- ся в первоначальном состоянии. Например:
    items = [1,2,3]
    with ListTransaction(items) as working:
    working.append(4)
    working.append(5)
    print(items) # Выведет [1,2,3,4,5]
    ёё
    try:
    with ListTransaction(items) as working:
    working.append(6)
    working.append(7)
    raise RuntimeError(“Немножко смошенничаем!”)
    except RuntimeError:
    pass print(items) # Выведет [1,2,3,4,5]
    Модуль contextlib упрощает реализацию собственных менеджеров контек- ста за счет обертывания функций-генераторов. Например:
    from contextlib import contextmanager
    @contextmanager

    128
    Глава 5. Структура программы и управление потоком выполнения def ListTransaction(thelist):
    workingcopy = list(thelist)
    yield workingcopy
    # Изменить оригинальный список, только если не возникло ошибок thelist[:] = workingcopy
    В этом примере значение, передаваемое инструкции yield, использует- ся, как возвращаемое значение метода __enter__(). После вызова метода
    __exit__()
    выполнение будет продолжено с инструкции, следующей за ин- струкцией yield. Если в контексте возникло исключение, оно проявится как исключение в функции-генераторе. При необходимости функция мо- жет перехватить и обработать исключение, но в данном случае оно продол- жит свое распространение за пределы генератора и, возможно, будет обра- ботано где-то в другом месте.
    Отладочные проверки
    и переменная __debug__
    Инструкция assert позволяет добавлять в программу отладочный код.
    В общем случае инструкция assert имеет следующий вид:
    assert test [, msg]
    где test – выражение, которое должно возвращать значение True или False.
    Если выражение test возвратит значение False, инструкция assert возбудит исключение AssertionError с переданным ему сообщением msg. Например:
    def write_data(file,data):
    assert file, “write_data: файл не определен!”
    ...
    Инструкция assert не должна содержать программный код, обеспечиваю- щий безошибочную работу программы, потому что он не будет выполнять- ся интерпретатором, работающим в оптимизированном режиме (этот ре- жим включается при запуске интерпретатора с ключом -O). В частности, будет ошибкой использовать инструкцию assert для проверки ввода поль- зователя. Обычно инструкции assert используются для проверки условий, которые всегда должны быть истинными; если такое условие нарушается, это можно рассматривать, как ошибку в программе, а не как ошибку поль- зователя.
    Например, если функция write_data() в примере выше была бы предназна- чена для взаимодействия с конечным пользователем, инструкцию assert следовало бы заменить обычной условной инструкцией if и предусмотреть обработку ошибок.
    Помимо инструкции assert в Python имеется встроенная переменная __de- de- bug__
    , доступная только для чтения, которая получает значение True, когда интерпретатор работает не в оптимизированном режиме (включается при запуске интерпретатора с ключом -O). Программы могут проверять значе- ние этой переменной, чтобы в случае необходимости выполнять дополни- тельную проверку на наличие ошибок. Внутренняя реализация перемен-

    Отладочные проверки и переменная __debug__
    129
    ной __debug__ в интерпретаторе оптимизирована так, что сама инструкция if в действительности не включается в текст программы. Если интерпрета- тор действует в обычном режиме, программный код, составляющий тело инструкции if __debug__, просто включается в текст программы, без са- мой инструкции if. При работе в оптимизированном режиме инструкция if __debug__
    и все связанные с ней инструкции полностью удаляются из программы.
    Использование инструкции assert и переменной __debug__ обеспечива- ет возможность эффективной разработки программ, работающих в двух режимах. Например, для работы в отладочном режиме можно добавить в свой программный код произвольное количество проверок, чтобы убе- диться в его безошибочной работе. При работе в оптимизированном режи- ме все эти проверки будут удалены и уже не будут отрицательно влиять на производительность.

    1   ...   6   7   8   9   10   11   12   13   ...   82


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