Ошибка при компиляции питон что значит

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

Синтаксис обработки исключений

Прежде чем переходить к обсуждению того, почему обработка исключений так важна, и рассматривать встроенные в Python исключения, важно понять, что есть тонкая грань между понятиями ошибки и исключения.

Ошибку нельзя обработать, а исключения Python обрабатываются при выполнении программы. Ошибка может быть синтаксической, но существует и много видов исключений, которые возникают при выполнении и не останавливают программу сразу же. Ошибка может указывать на критические проблемы, которые приложение и не должно перехватывать, а исключения — состояния, которые стоит попробовать перехватить. Ошибки — вид непроверяемых и невозвратимых ошибок, таких как OutOfMemoryError, которые не стоит пытаться обработать.

Обработка исключений делает код более отказоустойчивым и помогает предотвращать потенциальные проблемы, которые могут привести к преждевременной остановке выполнения. Представьте код, который готов к развертыванию, но все равно прекращает работу из-за исключения. Клиент такой не примет, поэтому стоит заранее обработать конкретные исключения, чтобы избежать неразберихи.

Ошибки могут быть разных видов:

  • Синтаксические
  • Недостаточно памяти
  • Ошибки рекурсии
  • Исключения

Разберем их по очереди.

Синтаксические ошибки (SyntaxError)

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

Рассмотрим на примере.

a = 8
b = 10
c = a b
File "", line 3
 c = a b
       ^
SyntaxError: invalid syntax

Стрелка вверху указывает на место, где интерпретатор получил ошибку при попытке исполнения. Знак перед стрелкой указывает на причину проблемы. Для устранения таких фундаментальных ошибок Python будет делать большую часть работы за программиста, выводя название файла и номер строки, где была обнаружена ошибка.

Недостаточно памяти (OutofMemoryError)

Ошибки памяти чаще всего связаны с оперативной памятью компьютера и относятся к структуре данных под названием “Куча” (heap). Если есть крупные объекты (или) ссылки на подобные, то с большой долей вероятности возникнет ошибка OutofMemory. Она может появиться по нескольким причинам:

  • Использование 32-битной архитектуры Python (максимальный объем выделенной памяти невысокий, между 2 и 4 ГБ);
  • Загрузка файла большого размера;
  • Запуск модели машинного обучения/глубокого обучения и много другое;

Обработать ошибку памяти можно с помощью обработки исключений — резервного исключения. Оно используется, когда у интерпретатора заканчивается память и он должен немедленно остановить текущее исполнение. В редких случаях Python вызывает OutofMemoryError, позволяя скрипту каким-то образом перехватить самого себя, остановить ошибку памяти и восстановиться.

Но поскольку Python использует архитектуру управления памятью из языка C (функция malloc()), не факт, что все процессы восстановятся — в некоторых случаях MemoryError приведет к остановке. Следовательно, обрабатывать такие ошибки не рекомендуется, и это не считается хорошей практикой.

Ошибка рекурсии (RecursionError)

Эта ошибка связана со стеком и происходит при вызове функций. Как и предполагает название, ошибка рекурсии возникает, когда внутри друг друга исполняется много методов (один из которых — с бесконечной рекурсией), но это ограничено размером стека.

Все локальные переменные и методы размещаются в стеке. Для каждого вызова метода создается стековый кадр (фрейм), внутрь которого помещаются данные переменной или результат вызова метода. Когда исполнение метода завершается, его элемент удаляется.

Чтобы воспроизвести эту ошибку, определим функцию recursion, которая будет рекурсивной — вызывать сама себя в бесконечном цикле. В результате появится ошибка StackOverflow или ошибка рекурсии, потому что стековый кадр будет заполняться данными метода из каждого вызова, но они не будут освобождаться.

def recursion():
    return recursion()

recursion()
---------------------------------------------------------------------------

RecursionError                            Traceback (most recent call last)

 in 
----> 1 recursion()


 in recursion()
      1 def recursion():
----> 2     return recursion()


... last 1 frames repeated, from the frame below ...


 in recursion()
      1 def recursion():
----> 2     return recursion()


RecursionError: maximum recursion depth exceeded

Ошибка отступа (IndentationError)

Эта ошибка похожа по духу на синтаксическую и является ее подвидом. Тем не менее она возникает только в случае проблем с отступами.

Пример:

for i in range(10):
    print('Привет Мир!')
  File "", line 2
    print('Привет Мир!')
        ^
IndentationError: expected an indented block

Исключения

Даже если синтаксис в инструкции или само выражение верны, они все равно могут вызывать ошибки при исполнении. Исключения Python — это ошибки, обнаруживаемые при исполнении, но не являющиеся критическими. Скоро вы узнаете, как справляться с ними в программах Python. Объект исключения создается при вызове исключения Python. Если скрипт не обрабатывает исключение явно, программа будет остановлена принудительно.

Программы обычно не обрабатывают исключения, что приводит к подобным сообщениям об ошибке:

Ошибка типа (TypeError)

a = 2
b = 'PythonRu'
a + b
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

 in 
      1 a = 2
      2 b = 'PythonRu'
----> 3 a + b


TypeError: unsupported operand type(s) for +: 'int' and 'str'

Ошибка деления на ноль (ZeroDivisionError)

10 / 0
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

 in 
----> 1 10 / 0


ZeroDivisionError: division by zero

Есть разные типы исключений в Python и их тип выводится в сообщении: вверху примеры TypeError и ZeroDivisionError. Обе строки в сообщениях об ошибке представляют собой имена встроенных исключений Python.

Оставшаяся часть строки с ошибкой предлагает подробности о причине ошибки на основе ее типа.

Теперь рассмотрим встроенные исключения Python.

Встроенные исключения

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

Прежде чем переходить к разбору встроенных исключений быстро вспомним 4 основных компонента обработки исключения, как показано на этой схеме.

  • Try: он запускает блок кода, в котором ожидается ошибка.
  • Except: здесь определяется тип исключения, который ожидается в блоке try (встроенный или созданный).
  • Else: если исключений нет, тогда исполняется этот блок (его можно воспринимать как средство для запуска кода в том случае, если ожидается, что часть кода приведет к исключению).
  • Finally: вне зависимости от того, будет ли исключение или нет, этот блок кода исполняется всегда.

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

Ошибка прерывания с клавиатуры (KeyboardInterrupt)

Исключение KeyboardInterrupt вызывается при попытке остановить программу с помощью сочетания Ctrl + C или Ctrl + Z в командной строке или ядре в Jupyter Notebook. Иногда это происходит неумышленно и подобная обработка поможет избежать подобных ситуаций.

В примере ниже если запустить ячейку и прервать ядро, программа вызовет исключение KeyboardInterrupt. Теперь обработаем исключение KeyboardInterrupt.

try:
    inp = input()
    print('Нажмите Ctrl+C и прервите Kernel:')
except KeyboardInterrupt:
    print('Исключение KeyboardInterrupt')
else:
    print('Исключений не произошло')

Исключение KeyboardInterrupt

Стандартные ошибки (StandardError)

Рассмотрим некоторые базовые ошибки в программировании.

Арифметические ошибки (ArithmeticError)

  • Ошибка деления на ноль (Zero Division);
  • Ошибка переполнения (OverFlow);
  • Ошибка плавающей точки (Floating Point);

Все перечисленные выше исключения относятся к классу Arithmetic и вызываются при ошибках в арифметических операциях.

Деление на ноль (ZeroDivisionError)

Когда делитель (второй аргумент операции деления) или знаменатель равны нулю, тогда результатом будет ошибка деления на ноль.

try:  
    a = 100 / 0
    print(a)
except ZeroDivisionError:  
    print("Исключение ZeroDivisionError." )
else:  
    print("Успех, нет ошибок!")
Исключение ZeroDivisionError.

Переполнение (OverflowError)

Ошибка переполнение вызывается, когда результат операции выходил за пределы диапазона. Она характерна для целых чисел вне диапазона.

try:  
    import math
    print(math.exp(1000))
except OverflowError:  
    print("Исключение OverFlow.")
else:  
    print("Успех, нет ошибок!")
Исключение OverFlow.

Ошибка утверждения (AssertionError)

Когда инструкция утверждения не верна, вызывается ошибка утверждения.

Рассмотрим пример. Предположим, есть две переменные: a и b. Их нужно сравнить. Чтобы проверить, равны ли они, необходимо использовать ключевое слово assert, что приведет к вызову исключения Assertion в том случае, если выражение будет ложным.

try:  
    a = 100
    b = "PythonRu"
    assert a == b
except AssertionError:  
    print("Исключение AssertionError.")
else:  
    print("Успех, нет ошибок!")

Исключение AssertionError.

Ошибка атрибута (AttributeError)

При попытке сослаться на несуществующий атрибут программа вернет ошибку атрибута. В следующем примере можно увидеть, что у объекта класса Attributes нет атрибута с именем attribute.

class Attributes(obj):
    a = 2
    print(a)

try:
    obj = Attributes()
    print(obj.attribute)
except AttributeError:
    print("Исключение AttributeError.")

2
Исключение AttributeError.

Ошибка импорта (ModuleNotFoundError)

Ошибка импорта вызывается при попытке импортировать несуществующий (или неспособный загрузиться) модуль в стандартном пути или даже при допущенной ошибке в имени.

import nibabel
---------------------------------------------------------------------------

ModuleNotFoundError                       Traceback (most recent call last)

 in 
----> 1 import nibabel


ModuleNotFoundError: No module named 'nibabel'

Ошибка поиска (LookupError)

LockupError выступает базовым классом для исключений, которые происходят, когда key или index используются для связывания или последовательность списка/словаря неверна или не существует.

Здесь есть два вида исключений:

  • Ошибка индекса (IndexError);
  • Ошибка ключа (KeyError);

Ошибка ключа

Если ключа, к которому нужно получить доступ, не оказывается в словаре, вызывается исключение KeyError.

try:  
    a = {1:'a', 2:'b', 3:'c'}  
    print(a[4])  
except LookupError:  
    print("Исключение KeyError.")
else:  
    print("Успех, нет ошибок!")

Исключение KeyError.

Ошибка индекса

Если пытаться получить доступ к индексу (последовательности) списка, которого не существует в этом списке или находится вне его диапазона, будет вызвана ошибка индекса (IndexError: list index out of range python).

try:
    a = ['a', 'b', 'c']  
    print(a[4])  
except LookupError:  
    print("Исключение IndexError, индекс списка вне диапазона.")
else:  
    print("Успех, нет ошибок!")
Исключение IndexError, индекс списка вне диапазона.

Ошибка памяти (MemoryError)

Как уже упоминалось, ошибка памяти вызывается, когда операции не хватает памяти для выполнения.

Ошибка имени (NameError)

Ошибка имени возникает, когда локальное или глобальное имя не находится.

В следующем примере переменная ans не определена. Результатом будет ошибка NameError.

try:
    print(ans)
except NameError:  
    print("NameError: переменная 'ans' не определена")
else:  
    print("Успех, нет ошибок!")
NameError: переменная 'ans' не определена

Ошибка выполнения (Runtime Error)

Ошибка «NotImplementedError»
Ошибка выполнения служит базовым классом для ошибки NotImplemented. Абстрактные методы определенного пользователем класса вызывают это исключение, когда производные методы перезаписывают оригинальный.

class BaseClass(object):
    """Опередляем класс"""
    def __init__(self):
        super(BaseClass, self).__init__()
    def do_something(self):
	# функция ничего не делает
        raise NotImplementedError(self.__class__.__name__ + '.do_something')

class SubClass(BaseClass):
    """Реализует функцию"""
    def do_something(self):
        # действительно что-то делает
        print(self.__class__.__name__ + ' что-то делает!')

SubClass().do_something()
BaseClass().do_something()

SubClass что-то делает!



---------------------------------------------------------------------------

NotImplementedError                       Traceback (most recent call last)

 in 
     14
     15 SubClass().do_something()
---> 16 BaseClass().do_something()


 in do_something(self)
      5     def do_something(self):
      6         # функция ничего не делает
----> 7         raise NotImplementedError(self.__class__.__name__ + '.do_something')
      8
      9 class SubClass(BaseClass):


NotImplementedError: BaseClass.do_something

Ошибка типа (TypeError)

Ошибка типа вызывается при попытке объединить два несовместимых операнда или объекта.

В примере ниже целое число пытаются добавить к строке, что приводит к ошибке типа.

try:
    a = 5
    b = "PythonRu"
    c = a + b
except TypeError:
    print('Исключение TypeError')
else:
    print('Успех, нет ошибок!')

Исключение TypeError

Ошибка значения (ValueError)

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

В этом примере встроенная операция float получат аргумент, представляющий собой последовательность символов (значение), что является недопустимым значением для типа: число с плавающей точкой.

try:
    print(float('PythonRu'))
except ValueError:
    print('ValueError: не удалось преобразовать строку в float: 'PythonRu'')
else:
    print('Успех, нет ошибок!')
ValueError: не удалось преобразовать строку в float: 'PythonRu'

Пользовательские исключения в Python

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

Это можно сделать, создав новый класс, который будет наследовать из класса Exception в Python.

class UnAcceptedValueError(Exception):   
    def __init__(self, data):    
        self.data = data
    def __str__(self):
        return repr(self.data)

Total_Marks = int(input("Введите общее количество баллов: "))
try:
    Num_of_Sections = int(input("Введите количество разделов: "))
    if(Num_of_Sections < 1):
        raise UnAcceptedValueError("Количество секций не может быть меньше 1")
except UnAcceptedValueError as e:
    print("Полученная ошибка:", e.data)

Введите общее количество баллов: 10
Введите количество разделов: 0
Полученная ошибка: Количество секций не может быть меньше 1

В предыдущем примере если ввести что-либо меньше 1, будет вызвано исключение. Многие стандартные исключения имеют собственные исключения, которые вызываются при возникновении проблем в работе их функций.

Недостатки обработки исключений в Python

У использования исключений есть свои побочные эффекты, как, например, то, что программы с блоками try-except работают медленнее, а количество кода возрастает.

Дальше пример, где модуль Python timeit используется для проверки времени исполнения 2 разных инструкций. В stmt1 для обработки ZeroDivisionError используется try-except, а в stmt2if. Затем они выполняются 10000 раз с переменной a=0. Суть в том, чтобы показать разницу во времени исполнения инструкций. Так, stmt1 с обработкой исключений занимает больше времени чем stmt2, который просто проверяет значение и не делает ничего, если условие не выполнено.

Поэтому стоит ограничить использование обработки исключений в Python и применять его в редких случаях. Например, когда вы не уверены, что будет вводом: целое или число с плавающей точкой, или не уверены, существует ли файл, который нужно открыть.

import timeit
setup="a=0"
stmt1 = '''
try:
    b=10/a
except ZeroDivisionError:
    pass'''

stmt2 = '''
if a!=0:
    b=10/a'''

print("time=",timeit.timeit(stmt1,setup,number=10000))
print("time=",timeit.timeit(stmt2,setup,number=10000))

time= 0.003897680000136461
time= 0.0002797570000439009

Выводы!

Как вы могли увидеть, обработка исключений помогает прервать типичный поток программы с помощью специального механизма, который делает код более отказоустойчивым.

Обработка исключений — один из основных факторов, который делает код готовым к развертыванию. Это простая концепция, построенная всего на 4 блоках: try выискивает исключения, а except их обрабатывает.

Очень важно поупражняться в их использовании, чтобы сделать свой код более отказоустойчивым.

Создание программного обеспечения — сложный процесс, осуществляемый коллективом специалистов (реже — одним человеком), а людям свойственно допускать ошибки (человеческий фактор). В связи с этим, код необходимо писать так, чтобы сводить возможные ошибки к минимуму, а также иметь возможность их эффективно определять, искать и обрабатывать, что является одним из признаков качественного программного обеспечения.

Содержание

  • Известные ошибки в ПО

    • 1962 г.: ракета Маринер-1

    • 1985 г.: аппарат лучевой терапии Therac-25

    • 1991 г.: ЗРК Patriot

    • 2000 г.: Проблема 2000 года (Y2K)

    • 2009-2011 г.: отзыв автомобилей Toyota

  • Определение и разновидности ошибок

    • Синтаксические ошибки

    • Логические (семантические) ошибки

    • Ошибки времени выполнения

    • Недокументированное поведение

  • Поиск ошибок и отладка программы

  • Подходы к обработке ошибок

  • Обработка исключений в Python

    • Понятия исключения

    • Конструкция try

    • Возбуждение исключений (raise)

    • Особенности обработки исключений внутри функций

    • Утверждения (assert)

    • Исключения или утверждения?

  • Рекомендации

7.1.1. Известные ошибки в ПО¶

История знает множество примеров, где программные ошибки стоили не только огромных денег, но и человеческих жизней 6 7:

7.1.1.1. 1962 г.: ракета Маринер-1¶

Маринер-1 — космический аппарат США для изучения Венеры (Рисунок 7.1.1).

_images/07_01_01.png

Рисунок 7.1.1 — Ракета Маринер-1 9

  • Описание и причина:

    Программист сделал ошибку, когда переводил рукописные математические формулы в код. Символ логического отрицания ¬ он принял за минус, и это привело к тому, что ракета воспринимала нормальные скорости как критические и из-за этого сбилась с курса.

  • Примерный ущерб / потери

    Никто не погиб, однако экономические потери составили 18,3 млн. долларов.

7.1.1.2. 1985 г.: аппарат лучевой терапии Therac-25¶

Therac-25 — канадский аппарат лучевой терапии (Рисунок 7.1.2).

_images/07_01_02.png

Рисунок 7.1.2 — Аппарат лучевой терапии `Therac-25 10

  • Описание и причина:

    Неисправность была вызвана тем, что в проекте использовались библиотеки с ошибками, входящие в состав ПО аппарата Therac-20, что и привело к фатальным последствиям. В коде была найдена довольно распространенная ошибка многопоточности, называемое состоянием гонки. Тем не менее ошибку не заметили, так как Therac-20 работал исправно из-за дополнительных (аппаратных) мер предосторожности.

  • Примерный ущерб / потери

    Умерло 2 человека, 4 получили серьезное облучение.

7.1.1.3. 1991 г.: ЗРК Patriot¶

Patriot — американский зенитный ракетный комплекс (Рисунок 7.1.3)

_images/07_01_03.png

Рисунок 7.1.3 — ЗРК Patriot 11

  • Описание и причина:

    Во время Войны в Персидском заливе по казармам подразделений США был нанесен ракетный удар иракскими ракетами типа Р-17 (советская баллистическая ракета). Ни одна из ракет не была перехвачена, и удар достиг цели.

    В программном обеспечении ЗРК, отвечающем за ведение и перехват цели, присутствовала ошибка, из-за которой со временем внутренние часы постепенно отходили от истинного значения времени: системное время хранилось как целое число в 24-битном регистре с точностью до 0,1 секунды; при итоговом расчете данные переводились в вещественное число.

    Проблема заключалась в том, что число (cfrac{1}{10}) не имеет точного представления в двоичной системе счисления:

    • (cfrac{1}{10}_{10} = 0,0001100110011001100110011001100…_{2});

    • (cfrac{1}{10}_{10} = 0,00011001100110011001100_{2}) (24-битное целое в системе Patriot);

    • ошибка 1 измерения: ~ (0,000000095_{10});

    • ошибка за 100 часов работы (0,000000095 cdot 10 cdot 60 cdot 60 cdot 100 = 0,34) с.;

    • ракета Р-17 летит со скоростью 1676 м/c, и проходит за 0,34 с. больше полукилометра.

    Данной ошибки в измерениях было достаточно, чтобы ракета преодолела радиус поражения Patriot (Рисунок 7.1.4, Видео 7.1.1).

    _images/07_01_04.png

    Рисунок 7.1.4 — Неправильное определение зоны пролета ракеты 12

    Видео 7.1.1 — Демонстрация ошибки ПО Patriot

  • Примерный ущерб / потери

    Погибло 28 американских солдат и еще двести получили ранения.

7.1.1.4. 2000 г.: Проблема 2000 года (Y2K)¶

  • Описание и причина:

    Разработчики программного обеспечения, выпущенного в XX веке, зачастую использовали два знака для представления года в датах: например, 1 января 1961 года представлялось как «01.01.61». При наступлении 1 января 2000 года при двузначном представлении года после 99 наступал 00 год (т.е. 99 + 1 = 00), что интерпретировалось многими старыми программами как 1900 год. Сложность была еще и в том, что многие программы обращались к вычислению дат вперед (например, при составлении плана закупок, планировании даты полета и т.д.) (Рисунок 7.1.5).

    _images/07_01_05.png

    Рисунок 7.1.5 — Табло показывает 3 января 1900 года, вместо 3 января 2000 года. Франция 13

  • Примерный ущерб / потери

    30-300 млрд. долларов.

7.1.1.5. 2009-2011 г.: отзыв автомобилей Toyota¶

  • Описание и причина:

    Неисправность в дроссельной заслонке (регулирует количество горючей смеси, поступающей в цилиндры двигателя внутреннего сгорания) с электронным контролем (ETC) приводила к случайным ускорениям автомобиля (Видео 7.1.2).

    Видео 7.1.2 — Случайное ускорение автомобиля

    В ходе десятимесячного расследования специалисты NASA выявили, что программное обеспечение не соответствует стандартам MISRA (англ. Motor Industry Software Reliability Association) и содержит 7134 нарушения. Представители Toyota ответили, что у них свои собственные стандарты.

    20 декабря 2010 года Тойота отвергнула обвинения, но выплатила 16 млрд. долларов в досудебном порядке по искам, выпустила обновление ПО для некоторых моделей машин и отозвала 5,5 млн. автомобилей 8 (Рисунок 7.1.6).

    _images/07_01_06.png

    Рисунок 7.1.6 — Lexus ES 350 2007-2010 — одна из моделей с неисправностью 14

  • Примерный ущерб / потери

    Погибло не менее 89 человек, многомиллиардные потери компании.

7.1.2. Определение и разновидности ошибок¶

Ошибка (также баг от англ. Software Bug) — неполадка в программе, из-за которой она ведет себя неопределенно, выдавая неожиданный результат.

Основные категории ошибок:

  • синтаксические;

  • логические;

  • ошибки времени выполнения;

  • недокументированное поведение.

7.1.2.1. Синтаксические ошибки¶

  • Причина:

    Несоответствие синтаксису языка программирования. Для компилируемых языков программирования синтаксическая ошибка не позволит выполнить компиляцию.

  • Пример:

    >>> for i in range(10)
      File "<stdin>", line 1
        for i in range(10)
                         ^
    SyntaxError: invalid syntax
    

7.1.2.2. Логические (семантические) ошибки¶

  • Причина:

    Несоответствие правильной логике работы программы.

  • Пример:

    >>> def avg_of_2(a, b):
    ...     return a + b / 2
    ...
    >>> avg_of_2(4, 8)  # Вернет 8 вместо 6
    

7.1.2.3. Ошибки времени выполнения¶

  • Причина:

    Любая неполадка, возникающая во время работы программы, например: целочисленное деление на ноль, ошибка при чтении файла, исчерпание доступной памяти и др.

  • Пример:

    >>> a = 5
    >>> b = 0
    >>> a / b
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
    ZeroDivisionError: division by zero
    

7.1.2.4. Недокументированное поведение¶

  • Причина:

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

  • Пример:

    Одним из наиболее известных примеров являются SQL-инъекции — внедрение в запрос произвольного SQL-кода.

    -- Код на сервере
    txtUserId = getRequestString("UserId");
    txtSQL = "SELECT * FROM Users WHERE UserId = " + txtUserId;
    
    -- "Стандартный" вызов на клиенте при UserId = 105 сформирует запрос
    SELECT * FROM Users WHERE UserId = 105
    
    -- Передача в качестве 'UserId' значения
    -- "105; DROP TABLE Suppliers" приведет к удалению таблицы 'Suppliers'
    SELECT * FROM Users WHERE UserId = 105; DROP TABLE Suppliers
    

Синтаксические и ошибки времени выполнения приводят к немедленному завершению (краху (англ. Crash)) выполнения программы в отличие от логических ошибок, после которых программа может продолжить работу. Пример краха программного обеспечения приведен на Видео 7.1.3.

Видео 7.1.3 — Презентация ОС Windows 98

7.1.3. Поиск ошибок и отладка программы¶

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

Существуют две взаимодополняющие технологии отладки:

  • использование отладчиков: программ, которые включают в себя пользовательский интерфейс для пошагового выполнения программы: оператор за оператором, функция за функцией, с остановками на некоторых строках исходного кода или при достижении определенного условия (Рисунок 7.1.7);

    _images/07_01_07.png

    Рисунок 7.1.7 — Пример отладки в IDE PyCharm: выполнение «заморожено» на точке останова (англ. Breakpoint), при этом IDE отображает текущие значения переменных, дополнительные окна и параметры

  • вывод текущего состояния программы с помощью расположенных в критических точках программы операторов вывода — на экран, принтер, громкоговоритель или в файл. Вывод отладочных сведений в файл называется журналированием (также логгированием или аудитом) (Листинг 7.1.1).

    Листинг 7.1.1 — Пример отладочного вывода с использованием функции print() | скачать

    import random
    
    a = random.randint(1, 100)
    b = random.randint(1, 100)
    
    print(a, b)  # 44 97
    
    print(a**2 + b**2)  # 11345
    

7.1.4. Подходы к обработке ошибок¶

При написании кода необходимо предусматривать, что в определенном месте программы может возникнуть ошибка и дополнять код на случай ее возникновения.

Существует два ключевых подхода программирования реакции на возможные ошибки:

  1. «Семь раз отмерь, один раз отрежь» — LBYL (англ. Look Before You Leap);

    Суть подхода: прежде чем выполнить основное действие выполняются проверки — не получится ли деления на ноль, есть ли файл на диске и т.д.

  2. «Легче попросить прощения, чем разрешения» — EAFP (англ. «It’s Easier To Ask Forgiveness Than Permission»).

    Суть подхода: сначала выполняется основное действие, а затем, если возникнут, обрабатываются ошибки. Данный механизм поддерживается в различных языках программирования и называется обработкой исключений, а сама ошибочная ситуация — исключением.

В Листинге 7.1.2 приведен пример сравнения двух подходов.

Листинг 7.1.2 — Псевдокод функций, использующих разные подходы к обработке ошибок: «Семь раз отмерь, один раз отрежь» и «Легче попросить прощения, чем разрешения»

Обе функции возвращают решение линейного уравнения и НИЧЕГО, если 'a' = 0


ФУНКЦИЯ найти_корень_1(a, b):
    ЕСЛИ a не равно 0
        ВЕРНУТЬ -b / a
    ИНАЧЕ
        ВЕРНУТЬ НИЧЕГО


ФУНКЦИЯ найти_корень_2(a, b):
    ОПАСНЫЙ БЛОК КОДА      # Внутри данного блока пишется код, который
        ВЕРНУТЬ -b / a     # потенциально может привести к ошибкам
    ЕСЛИ ПРОИЗОШЛА ОШИБКА  # В случае деления на 0 попадаем сюда
        ВЕРНУТЬ НИЧЕГО

Подход «Семь раз отмерь, один раз отрежь» имеет определенные минусы:

  • проверки могут уменьшить читаемость и ясность основного кода;

  • код проверки может дублировать значительную часть работы, осуществляемой основным кодом;

  • разработчик может легко допустить ошибку, забыв какую-либо из проверок;

  • ситуация может изменится между моментом проверки и моментом выполнения операции.

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

7.1.5. Обработка исключений в Python¶

7.1.5.1. Понятия исключения¶

При возникновении ошибки времени выполнения Python создает (возбуждает) специальный объект — исключение, который позволяет однозначно характеризовать возникшую ошибочную ситуацию. Выбор подходящего исключения происходит из встроенной иерархии классов-исключений (фрагмент):

  • BaseException (базовое исключение)

    • SystemExit (исключение, порождаемое функцией sys.exit() при выходе из программы)

    • KeyboardInterrupt (прерывании программы пользователем, Ctrl+C)

    • Exception (базовое несистемное исключение)

      • ArithmeticError (арифметическая ошибка)

        • FloatingPointError (неудачное выполнение операции с плавающей запятой)

        • OverflowError (результат арифметической операции слишком велик для представления)

        • ZeroDivisionError (деление на ноль)

      • LookupError (некорректный индекс или ключ)

        • IndexError (индекс не входит в диапазон элементов)

        • KeyError (несуществующий ключ)

      • MemoryError (недостаточно памяти)

      • NameError (не найдено переменной с таким именем)

      • OSError (ошибка, связанная с ОС — есть подклассы, например FileNotFoundError)

      • SyntaxError (синтаксическая ошибка, включает классы IndentationError и TabError)

      • SystemError (внутренняя ошибка)

      • TypeError (операция применена к объекту несоответствующего типа)

      • ValueError (аргумент правильного типа, но некорректного значения)

Пример встроенного возбуждения исключения:

>>> "я - строка" / 5
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: unsupported operand type(s) for /: 'str' and 'int'

7.1.5.2. Конструкция try

Придерживаясь идеологии «Легче попросить прощения, чем разрешения», Python предусматривает конструкцию try для обработки возникающих исключений.

try
except
else
finally
try:                              # (try строго 1)
    try_ suite                    # код, который может выполниться с ошибкой
except exception_group1 as var1:  # (except - 0 (если есть finally) и более)
    except_suite1                 # код, выполняемый в случае исключения 'exception_group1'
...                               # ссылка на исключение может быть записана в 'var1'
except exception_groupN as varN:
    except_suiteN                 # код, выполняемый в случае исключения 'exception_groupN'
...                               # except-блоков может быть произвольное кол-во
else:                             # (else - 0 или 1)
    else_suite                    # выполняется, если try не завершен преждевременно (например, break)
finally:                          # (finally - 0 или 1)
    finally_suite                 # код, который должен выполнится всегда (была ошибка выше или нет)

Ход выполнения:

  • код, который потенциально может привести к ошибке, помещается в блок try;

  • в случае ошибки, код немедленно завершается и переходит в обработчик except (если он указан для соответствующего исключения);

  • после поток выполнения переходит к else (если исключений не было) и finally (в любом случае).

На Рисунке 7.1.8 приведены общие варианты потока выполнения программы при обработке исключений.

_images/07_01_08.png

Рисунок 7.1.8 — Варианты потока выполнения программы при обработке исключений 4

Обработка исключений (и соответственно идеология «Легче попросить прощения, чем разрешения») — предпочитаемый способ в Python, а использование блоков зависит от конкретной ситуации.

Наиболее общий вариант обработки исключений приведен в Листинге 7.1.3.

Листинг 7.1.3 — Наиболее простой способ обработки исключений | скачать

try:
    x = int(input("Введите целое число x (для вычисления 1/x): "))
    res = 1 / x

    print("1/{} = {:.2f}".format(x, res))
except:
    print("Произошла ошибка!")

# --------------
# Примеры вывода:

# Введите целое число x (для вычисления 1/x): 3
# 1/3 = 0.33

# Введите целое число x (для вычисления 1/x): qwerty
# Произошла ошибка!

Подобный вариант обработки исключений не рекомендуется, т.к. блок except будет перехватывать любое исключение, что не позволит точно определить ошибку в коде. Улучшить код можно, добавив обработку исключения по классу (Листинг 7.1.4).

Листинг 7.1.4 — Обработка общего класса исключений Exception | скачать

try:
    x = int(input("Введите целое число x (для вычисления 1/x): "))
    res = 1 / x

    print("1/{} = {:.2f}".format(x, res))
except Exception as err:
    print("Произошла ошибка!")
    print("Тип:", type(err))
    print("Описание:", err)

# --------------
# Примеры вывода:

# Введите целое число x (для вычисления 1/x): 3
# 1/3 = 0.33

# Введите целое число x (для вычисления 1/x): 5.5
# Произошла ошибка!
# Тип: <class 'ValueError'>
# Описание: invalid literal for int() with base 10: '5.5'

Рекомендуемым способом обработки исключений является как можно большая конкретизация класса исключения (Листинг 7.1.5).

Листинг 7.1.5 — Обработка конкретных классов исключений | скачать

try:
    x = int(input("Введите целое число x (для вычисления 1/x): "))
    res = 1 / x

    print("1/{} = {:.2f}".format(x, res))
except ZeroDivisionError:
    print("На ноль делить нельзя!")
except ValueError as err:  # 'err' содержит ссылку на исключение
    print("Будьте внимательны:", err)
except (FileExistsError, FileNotFoundError):  # Исключения можно перечислять в виде кортежа
    print("Этого никогда не случится - мы не работаем с файлами")
except Exception as err:
    # Все, что не обработано выше и является потомком 'Exception',
    # будет обработано здесь
    print("Произошла ошибка!")
    print("Тип:", type(err))
    print("Описание:", err)

# --------------
# Примеры вывода:

# Введите целое число x (для вычисления 1/x): 3
# 1/3 = 0.33

# Введите целое число x (для вычисления 1/x): 0
# На ноль делить нельзя!

# Введите целое число x (для вычисления 1/x): qwerty
# Будьте внимательны: invalid literal for int() with base 10: 'qwerty'

7.1.5.3. Возбуждение исключений (raise

Исключения являются не только механизмом обработки ошибок, но и удобным средством управления потоком выполнения. Так, необходимое исключение можно возбудить вручную, когда это необходимо, используя конструкцию raise.

raise
raise exception(args)  # явное указание класса возбуждаемого исключения

# или

raise                  # 1) повторное возбуждение активного исключения (re-raise)
                       #    внутри блока except
                       # 2) 'TypeError' по умолчанию

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

В Листинге 7.1.6 приведен пример использование оператора raise.

Листинг 7.1.6 — Использование raise для управления потоком выполнения | скачать

MIN = 1
MAX = 10

try:
    x = int(input("Введите целое число от {} до {}: ".format(MIN, MAX)))

    if not MIN <= x <= MAX:
        # Возбудив исключение, его можно будет обработать в except
        # вместе с другими похожими исключениями
        raise ValueError("Число лежит вне интервала [{}; {}]!".format(MIN, MAX))

    print("Спасибо!")
except ValueError as err:  # 'err' содержит ссылку на исключение
    print("Будьте внимательны:", err)

# --------------
# Примеры вывода:

# Введите целое число от 1 до 10: 5
# Спасибо!

# Введите целое число от 1 до 10: 15
# Будьте внимательны: Число лежит вне интервала [1; 10]!

# Введите целое число от 1 до 10: qwerty
# Будьте внимательны: invalid literal for int() with base 10: 'qwerty'

7.1.5.4. Особенности обработки исключений внутри функций¶

Обработка исключений аналогично производится и внутри функций, однако, необходимо писать код так, чтобы вызывающий код знал о случившемся, если это влияет на его дальнейшую работу.

Разница в обработке исключений приведена в Листинге 7.1.7.

Листинг 7.1.7 — Различная обработка исключений в функции | скачать

# Ниже представлены 3 варианта обработки исключений в функциях
# Основное правило - обработка исключений внутри возможна и нужна, однако
#                    вызывающий код должен также знать о случившемся, если
#                    влияет на дальнейшую работу


def get_1_x(x):
    """Вернуть 1/x.

    Функция не обрабатывает исключения - ответственность на вызывающем коде.
    """
    return 1/x


def get_2_x(x):
    """Вернуть 2/x.

    Функция обрабатывает исключения, "затушив" ошибку - вызывающий код
    не будет знать, сработала функция правильно или нет.

    Данный способ использовать не рекомендуется!
    """
    try:
        return 2/x
    except Exception as e:
        print("Внутри произошла ошибка...", e)


def get_3_x(x):
    """Вернуть 3/x.

    Функция не только обрабатывает исключения, но перевозбуждает его:
    в результате вызывающий так же получает возникшее исключение.

    Внутренняя обработка исключений может быть полезна, если в целом результат
    функции не связан с внутренней ошибкой.
    """
    try:
        return 3/x
    except Exception as e:
        print("Внутри произошла ошибка...", e)
        raise

funcs = (get_1_x, get_2_x, get_3_x)
# Вызываем каждую функцию с "ошибочным" параметром
for func in funcs:
    try:
        print("-" * 50)
        print("Запущена функция:", func.__name__)
        print(func(0))
    except Exception as e:
        print("Произошла ошибка: {}.".format(e))

# -------------
# Пример вывода:

# --------------------------------------------------
# Запущена функция: get_1_x
# Произошла ошибка: division by zero.
# --------------------------------------------------
# Запущена функция: get_2_x
# Внутри произошла ошибка... division by zero
# None
# --------------------------------------------------
# Запущена функция: get_3_x
# Внутри произошла ошибка... division by zero
# Произошла ошибка: division by zero.

7.1.5.5. Утверждения (assert

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

В Python утверждения поддерживаются оператором assert.

assert
assert boolean_expression[, optional_expression]

# boolean_expression: логическое выражение для проверки
# optional_expression: необязательное сообщение (строка)

Если boolean_expression возвращает False, возбуждается исключение AssertionError с сообщением optional_expression (если задано).

Пример использования утверждений приведен в Листинге 7.1.8.

Листинг 7.1.8 — Использование утверждений в Python | скачать

# Использование оператора assert
# поможет отследить неверно реализованную функцию


def add_to_list(x, lst=[]):
    # Использование assert здесь оправдано - список всегда
    # подразумевается пустым
    assert len(lst) == 0, "Список должен быть пуст!"

    lst.append(x)
    return lst


print(add_to_list(1))
print(add_to_list(2))

# -------------
# Пример вывода:

# [1]
# Traceback (most recent call last):
#   File "07_01_08_a.py", line 15, in <module>
#     print(add_to_list(2))
#   File "07_01_08_a.py", line 8, in add_to_list
#     assert len(lst) == 0, "Список должен быть пуст!"
# AssertionError: Список должен быть пуст!

Примечание

В отличие от исключений утверждения являются отладочным инструментом и могут быть отключены при компиляции/интерпретации программы

7.1.5.6. Исключения или утверждения?¶

При выборе, использовать исключения или утверждения, придерживайтесь правил (Таблица 7.1.1).

Таблица 7.1.1 — Использовать исключения или утверждения?

Исключения

Утверждения

Обработка ошибок, которые могут произойти во время выполнения программы (неправильный ввод пользователя и т.п.)

Проверка ситуаций, которые предположительно не могут произойти

1

Проверка параметров общедоступных функций (исключения не могут быть отключены — проверка будет осуществлена всегда, а также класс исключения говорит о конкретном типе ошибки в отличие от утверждения)

Проверка предусловий, постусловий и инвариантов в необщедоступном коде (локальных функциях, внутреннем коде и т.д.)

2

Предоставление информации об ошибке пользователю

Предоставление информации об ошибке команде разработки

3

Восстановление из ошибочной ситуации (например, дальнейшая работа программы, если не удалось открыть файл)

Проверка невозможных ситуаций, свидетельствующих о серьезной ошибке в коде (например, выход за границы списка)

Примеры использования исключения и утверждений приведены в Листингах 7.1.9 (а-в).

Листинг 7.1.9 (а) — Использование исключений и утверждений в Python | скачать

# Исключения и утверждения могут проверять параметры функции,
# выступая в т.ч. более строгим вариантом документации


def fact(x):
    """Вернуть факториал 'x'.

    Не передавайте числа больше 15 во избежание переполнения памяти.
    """
    if x <= 1:
        return 1
    else:
        return x * fact(x-1)


def fact_save_1(x):
    assert x <= 15, 
        "Не передавайте числа больше 15 во избежание переполнения памяти"

    return fact(x)


def fact_save_2(x):
    if not x <= 15:
        raise ValueError("Не передавайте числа больше 15 во избежание "
                         "переполнения памяти")

    return fact(x)


print("{:>3} {:>20} {:>20}".format(*("x", "fact()", "fact_save()")))
for x in (5, 20):
    print("{:3}".format(x), end=" ")
    print("{:20}".format(fact(x)), end=" ")
    # print("{:20}".format(fact_save_1(x)))
    print("{:20}".format(fact_save_2(x)))

# -------------
# Пример вывода:

#   x               fact()          fact_save()
#   5                  120                  120
#  20  2432902008176640000 Traceback (most recent call last):
#   File "07_01_08_b.py", line 23, in <module>
#     print("{:20}".format(fact_save(x)))
#   File "07_01_08_b.py", line 15, in fact_save
#     assert x <= 15, "Не передавайте числа больше 15 во избежание переполнения памяти"
# AssertionError: Не передавайте числа больше 15 во избежание переполнения памяти
#
#   x               fact()          fact_save()
#   5                  120                  120
#  20  2432902008176640000 Traceback (most recent call last):
#   File "07_01_08_b.py", line 34, in <module>
#     print("{:20}".format(fact_save_2(x)))
#   File "07_01_08_b.py", line 24, in fact_save_2
#     raise ValueError("Не передавайте числа больше 15 во избежание "
# ValueError: Не передавайте числа больше 15 во избежание переполнения памяти

Листинг 7.1.9 (б) — Использование исключений и утверждений в Python | скачать

# Использование оператора assert для проверки входных и выходных данных


def make_call(accounts, account_id, mins, costs_per_min):
    """Списать со счета 'account' на 'value' баллов в случае звонка.

    Параметры:
        - accounts (dict): словарь со всеми счетами абонентов;
        - account_id (int): идентификатор абонента в словаре 'accounts';
        - mins (int): количество минут разговора;
        - costs_per_min (int): стоимость минуты разговора.
    """

    def get_costs(mins, costs_per_min):
        """Вернуть стоимость звонка.

        Параметры:
            - mins (int): количество минут разговора;
            - costs_per_min (int): стоимость минуты разговора.
        """
        return -mins * costs_per_min

    # Проверка типов
    assert isinstance(mins, int), "Параметр 'mins' имеет неверный тип!"
    assert isinstance(costs_per_min, (int, float)),
        "Параметр 'costs_per_min' имеет неверный тип!"

    # Проверка значений
    assert mins > 0, "Параметр 'mins' должен быть > 0"
    assert costs_per_min >= 0, "Параметр 'costs' должен быть >= 0"

    # Расчет (стоимость звонка не должна быть меньше 0)
    costs_total = get_costs(mins, costs_per_min)
    assert costs_total >= 0,
        "Расчет стоимости звонка был осуществлен неверно!"
    accounts[account_id] -= costs_total


# Словарь ID=Баланс
accounts = {"Василий Иванов": 100}
print(accounts)

try:
    make_call(accounts, "Василий Иванов", mins=4, costs_per_min=2)
except Exception as e:
    print("Во время списывания стоимости звонка произошла ошибка:", e)

print(accounts)

Листинг 7.1.9 (в) — Использование исключений и утверждений в Python | скачать

# Совместное использование исключений и утверждений

weekday_names = {
    1: "Понедельник",
    2: "Вторник",
    3: "Среда",
    4: "Четверг",
    5: "Пятница",
    6: "Суббота",
    7: "Воскресенье"
}


def weekday_name(weekday):
    """Вернуть название дня недели. Нумерация с 1.

    Параметры:
        weekday (int): номер дня недели.

    Исключения:
        - TypeError: 'weekday' не int;
        - ValueError: 'weekday' не число от 1 до 7.

    Результат:
        str: название дня недели.
    """
    # "Невозможная" ситуация - словарь 'weekday_names' может быть
    # "испорчен" - проверяется с помощью assert.
    assert weekday_names is not None and isinstance(weekday_names, dict), 
        "Внутренняя ошибка программы. Обратитесь в разрабочику."

    # Параметры функции проверяются с помощью исключений
    if not isinstance(weekday, int):
        raise TypeError("Параметр 'weekday' должен быть типа 'int'.")
    if weekday not in weekday_names:
        raise ValueError("Параметр 'weekday' должен быть целым числом "
                         "от 1 до 7.")

    return weekday_names[weekday]


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

while True:
    try:
        weekday = int(input("Введите номер дня недели (1-7): "))

        # if not 1 <= weekday <= 7:
        #     raise ValueError("Номер дня недели должен быть целым числом "
        #                      "от 1 до 7.")

        # Раскомментируйте код ниже, чтобы получить срабатывание assert
        # weekday_names = None

        print("Это -", weekday_name(weekday))

        break
    except TypeError as err:
        print("Проверьте, что введено целое число.")
    except ValueError as err:
        print("Проверьте, что введено целое число, и оно "
              "находится в допустимых границах.")
    except Exception as err:
        print("Ошибка при определении названия дня недели.")
        print(err)  # Запись в лог информации об ошибке

7.1.6. Рекомендации¶

Программный код должен быть написан с учетом того, что в любом его месте может возникнуть ошибка, для чего необходимо эффективно использовать соответствующие средства языка программирования:

  • код, который потенциально может привести к ошибкам, должен быть помещен в блок try;

  • блок except должен:

    • обрабатывать исключения максимально конкретно (указывать конкретные классы); стоит определять свои классы исключений, когда это это имеет смысл;

    • категорически не следует «тушить» исключения (писать пустой или бессмысленный except);

    • в блоках except следует снова возбуждать исключения (raise), которые не обрабатываются явно, передавая обработку в участок кода, который должен определять дальнейшие действия программы;

  • блок finally следует использовать для освобождения ресурсов (это может быть закрытие файла или сетевого соединения), независимо от того, прошла операция успешно или нет.


1

Sebesta, W.S Concepts of Programming languages. 10E; ISBN 978-0133943023.

2

Python — официальный сайт. URL: https://www.python.org/.

3

Python — FAQ. URL: https://docs.python.org/3/faq/programming.html.

4

Саммерфилд М. Программирование на Python 3. Подробное руководство. — М.: Символ-Плюс, 2009. — 608 с.: ISBN: 978-5-93286-161-5.

5

Лучано Рамальо. Python. К вершинам мастерства. — М.: ДМК Пресс , 2016. — 768 с.: ISBN: 978-5-97060-384-0, 978-1-491-94600-8.

6

5 худших багов в истории. URL: https://tproger.ru/articles/5-worst-bugs-in-history/.

7

List of software bugs. URL: https://en.wikipedia.org/wiki/List_of_software_bugs.

8

Toyota: 81 514 нарушений в коде. URL: https://habrahabr.ru/company/pvs-studio/blog/310862/.

9

Mariner-1. URL: https://ru.wikipedia.org/wiki/%D0%9C%D0%B0%D1%80%D0%B8%D0%BD%D0%B5%D1%80-1#/media/File:Atlas_Agena_with_Mariner_1.jpg.

10

Therac-25. URL: https://upload.wikimedia.org/wikipedia/commons/b/bd/Clinac_2rtg.jpg.

11

ЗРК Patriot. URL: http://vpk.name/file/img/Patriot_antimissile.t.jpg.

12

Incorrectly Calculated Range Gate. URL: https://hsto.org/files/853/04a/1dc/85304a1dc1b6499d94d5394436e42faf.jpg.

13

Табло показывает 3 января 1900 года, вместо 3 января 2000 года. Франция. URL: https://upload.wikimedia.org/wikipedia/commons/f/fb/Bug_de_l%27an_2000.jpg.

14

MY 2007–2010 Lexus ES 350. URL: http://pictures.topspeed.com/IMG/crop/201108/lexus-es-350-6_1600x0w.jpg.

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

Синтаксис обработки исключений

Прежде чем переходить к обсуждению того, почему обработка исключений так важна, и рассматривать встроенные в Python исключения, важно понять, что есть тонкая грань между понятиями ошибки и исключения.

Ошибку нельзя обработать, а исключения Python обрабатываются при выполнении программы. Ошибка может быть синтаксической, но существует и много видов исключений, которые возникают при выполнении и не останавливают программу сразу же. Ошибка может указывать на критические проблемы, которые приложение и не должно перехватывать, а исключения — состояния, которые стоит попробовать перехватить. Ошибки — вид непроверяемых и невозвратимых ошибок, таких как OutOfMemoryError, которые не стоит пытаться обработать.

Обработка исключений делает код более отказоустойчивым и помогает предотвращать потенциальные проблемы, которые могут привести к преждевременной остановке выполнения. Представьте код, который готов к развертыванию, но все равно прекращает работу из-за исключения. Клиент такой не примет, поэтому стоит заранее обработать конкретные исключения, чтобы избежать неразберихи.

Ошибки могут быть разных видов:

  • Синтаксические
  • Недостаточно памяти
  • Ошибки рекурсии
  • Исключения

Разберем их по очереди.

Синтаксические ошибки (SyntaxError)

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

Рассмотрим на примере.

a = 8
b = 10
c = a b
File "", line 3
 c = a b
       ^
SyntaxError: invalid syntax

Стрелка вверху указывает на место, где интерпретатор получил ошибку при попытке исполнения. Знак перед стрелкой указывает на причину проблемы. Для устранения таких фундаментальных ошибок Python будет делать большую часть работы за программиста, выводя название файла и номер строки, где была обнаружена ошибка.

Недостаточно памяти (OutofMemoryError)

Ошибки памяти чаще всего связаны с оперативной памятью компьютера и относятся к структуре данных под названием “Куча” (heap). Если есть крупные объекты (или) ссылки на подобные, то с большой долей вероятности возникнет ошибка OutofMemory. Она может появиться по нескольким причинам:

  • Использование 32-битной архитектуры Python (максимальный объем выделенной памяти невысокий, между 2 и 4 ГБ);
  • Загрузка файла большого размера;
  • Запуск модели машинного обучения/глубокого обучения и много другое;

Обработать ошибку памяти можно с помощью обработки исключений — резервного исключения. Оно используется, когда у интерпретатора заканчивается память и он должен немедленно остановить текущее исполнение. В редких случаях Python вызывает OutofMemoryError, позволяя скрипту каким-то образом перехватить самого себя, остановить ошибку памяти и восстановиться.

Но поскольку Python использует архитектуру управления памятью из языка C (функция malloc()), не факт, что все процессы восстановятся — в некоторых случаях MemoryError приведет к остановке. Следовательно, обрабатывать такие ошибки не рекомендуется, и это не считается хорошей практикой.

Ошибка рекурсии (RecursionError)

Эта ошибка связана со стеком и происходит при вызове функций. Как и предполагает название, ошибка рекурсии возникает, когда внутри друг друга исполняется много методов (один из которых — с бесконечной рекурсией), но это ограничено размером стека.

Все локальные переменные и методы размещаются в стеке. Для каждого вызова метода создается стековый кадр (фрейм), внутрь которого помещаются данные переменной или результат вызова метода. Когда исполнение метода завершается, его элемент удаляется.

Чтобы воспроизвести эту ошибку, определим функцию recursion, которая будет рекурсивной — вызывать сама себя в бесконечном цикле. В результате появится ошибка StackOverflow или ошибка рекурсии, потому что стековый кадр будет заполняться данными метода из каждого вызова, но они не будут освобождаться.

def recursion():
    return recursion()

recursion()
---------------------------------------------------------------------------

RecursionError                            Traceback (most recent call last)

 in 
----> 1 recursion()


 in recursion()
      1 def recursion():
----> 2     return recursion()


... last 1 frames repeated, from the frame below ...


 in recursion()
      1 def recursion():
----> 2     return recursion()


RecursionError: maximum recursion depth exceeded

Ошибка отступа (IndentationError)

Эта ошибка похожа по духу на синтаксическую и является ее подвидом. Тем не менее она возникает только в случае проблем с отступами.

Пример:

for i in range(10):
    print('Привет Мир!')
  File "", line 2
    print('Привет Мир!')
        ^
IndentationError: expected an indented block

Исключения

Даже если синтаксис в инструкции или само выражение верны, они все равно могут вызывать ошибки при исполнении. Исключения Python — это ошибки, обнаруживаемые при исполнении, но не являющиеся критическими. Скоро вы узнаете, как справляться с ними в программах Python. Объект исключения создается при вызове исключения Python. Если скрипт не обрабатывает исключение явно, программа будет остановлена принудительно.

Программы обычно не обрабатывают исключения, что приводит к подобным сообщениям об ошибке:

Ошибка типа (TypeError)

a = 2
b = 'PythonRu'
a + b
---------------------------------------------------------------------------

TypeError                                 Traceback (most recent call last)

 in 
      1 a = 2
      2 b = 'PythonRu'
----> 3 a + b


TypeError: unsupported operand type(s) for +: 'int' and 'str'

Ошибка деления на ноль (ZeroDivisionError)

10 / 0
---------------------------------------------------------------------------

ZeroDivisionError                         Traceback (most recent call last)

 in 
----> 1 10 / 0


ZeroDivisionError: division by zero

Есть разные типы исключений в Python и их тип выводится в сообщении: вверху примеры TypeError и ZeroDivisionError. Обе строки в сообщениях об ошибке представляют собой имена встроенных исключений Python.

Оставшаяся часть строки с ошибкой предлагает подробности о причине ошибки на основе ее типа.

Теперь рассмотрим встроенные исключения Python.

Встроенные исключения

BaseException
 +-- SystemExit
 +-- KeyboardInterrupt
 +-- GeneratorExit
 +-- Exception
      +-- StopIteration
      +-- StopAsyncIteration
      +-- ArithmeticError
      |    +-- FloatingPointError
      |    +-- OverflowError
      |    +-- ZeroDivisionError
      +-- AssertionError
      +-- AttributeError
      +-- BufferError
      +-- EOFError
      +-- ImportError
      |    +-- ModuleNotFoundError
      +-- LookupError
      |    +-- IndexError
      |    +-- KeyError
      +-- MemoryError
      +-- NameError
      |    +-- UnboundLocalError
      +-- OSError
      |    +-- BlockingIOError
      |    +-- ChildProcessError
      |    +-- ConnectionError
      |    |    +-- BrokenPipeError
      |    |    +-- ConnectionAbortedError
      |    |    +-- ConnectionRefusedError
      |    |    +-- ConnectionResetError
      |    +-- FileExistsError
      |    +-- FileNotFoundError
      |    +-- InterruptedError
      |    +-- IsADirectoryError
      |    +-- NotADirectoryError
      |    +-- PermissionError
      |    +-- ProcessLookupError
      |    +-- TimeoutError
      +-- ReferenceError
      +-- RuntimeError
      |    +-- NotImplementedError
      |    +-- RecursionError
      +-- SyntaxError
      |    +-- IndentationError
      |         +-- TabError
      +-- SystemError
      +-- TypeError
      +-- ValueError
      |    +-- UnicodeError
      |         +-- UnicodeDecodeError
      |         +-- UnicodeEncodeError
      |         +-- UnicodeTranslateError
      +-- Warning
           +-- DeprecationWarning
           +-- PendingDeprecationWarning
           +-- RuntimeWarning
           +-- SyntaxWarning
           +-- UserWarning
           +-- FutureWarning
           +-- ImportWarning
           +-- UnicodeWarning
           +-- BytesWarning
           +-- ResourceWarning

Прежде чем переходить к разбору встроенных исключений быстро вспомним 4 основных компонента обработки исключения, как показано на этой схеме.

  • Try: он запускает блок кода, в котором ожидается ошибка.
  • Except: здесь определяется тип исключения, который ожидается в блоке try (встроенный или созданный).
  • Else: если исключений нет, тогда исполняется этот блок (его можно воспринимать как средство для запуска кода в том случае, если ожидается, что часть кода приведет к исключению).
  • Finally: вне зависимости от того, будет ли исключение или нет, этот блок кода исполняется всегда.

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

Ошибка прерывания с клавиатуры (KeyboardInterrupt)

Исключение KeyboardInterrupt вызывается при попытке остановить программу с помощью сочетания Ctrl + C или Ctrl + Z в командной строке или ядре в Jupyter Notebook. Иногда это происходит неумышленно и подобная обработка поможет избежать подобных ситуаций.

В примере ниже если запустить ячейку и прервать ядро, программа вызовет исключение KeyboardInterrupt. Теперь обработаем исключение KeyboardInterrupt.

try:
    inp = input()
    print('Нажмите Ctrl+C и прервите Kernel:')
except KeyboardInterrupt:
    print('Исключение KeyboardInterrupt')
else:
    print('Исключений не произошло')

Исключение KeyboardInterrupt

Стандартные ошибки (StandardError)

Рассмотрим некоторые базовые ошибки в программировании.

Арифметические ошибки (ArithmeticError)

  • Ошибка деления на ноль (Zero Division);
  • Ошибка переполнения (OverFlow);
  • Ошибка плавающей точки (Floating Point);

Все перечисленные выше исключения относятся к классу Arithmetic и вызываются при ошибках в арифметических операциях.

Деление на ноль (ZeroDivisionError)

Когда делитель (второй аргумент операции деления) или знаменатель равны нулю, тогда результатом будет ошибка деления на ноль.

try:  
    a = 100 / 0
    print(a)
except ZeroDivisionError:  
    print("Исключение ZeroDivisionError." )
else:  
    print("Успех, нет ошибок!")
Исключение ZeroDivisionError.

Переполнение (OverflowError)

Ошибка переполнение вызывается, когда результат операции выходил за пределы диапазона. Она характерна для целых чисел вне диапазона.

try:  
    import math
    print(math.exp(1000))
except OverflowError:  
    print("Исключение OverFlow.")
else:  
    print("Успех, нет ошибок!")
Исключение OverFlow.

Ошибка утверждения (AssertionError)

Когда инструкция утверждения не верна, вызывается ошибка утверждения.

Рассмотрим пример. Предположим, есть две переменные: a и b. Их нужно сравнить. Чтобы проверить, равны ли они, необходимо использовать ключевое слово assert, что приведет к вызову исключения Assertion в том случае, если выражение будет ложным.

try:  
    a = 100
    b = "PythonRu"
    assert a == b
except AssertionError:  
    print("Исключение AssertionError.")
else:  
    print("Успех, нет ошибок!")

Исключение AssertionError.

Ошибка атрибута (AttributeError)

При попытке сослаться на несуществующий атрибут программа вернет ошибку атрибута. В следующем примере можно увидеть, что у объекта класса Attributes нет атрибута с именем attribute.

class Attributes(obj):
    a = 2
    print(a)

try:
    obj = Attributes()
    print(obj.attribute)
except AttributeError:
    print("Исключение AttributeError.")

2
Исключение AttributeError.

Ошибка импорта (ModuleNotFoundError)

Ошибка импорта вызывается при попытке импортировать несуществующий (или неспособный загрузиться) модуль в стандартном пути или даже при допущенной ошибке в имени.

import nibabel
---------------------------------------------------------------------------

ModuleNotFoundError                       Traceback (most recent call last)

 in 
----> 1 import nibabel


ModuleNotFoundError: No module named 'nibabel'

Ошибка поиска (LookupError)

LockupError выступает базовым классом для исключений, которые происходят, когда key или index используются для связывания или последовательность списка/словаря неверна или не существует.

Здесь есть два вида исключений:

  • Ошибка индекса (IndexError);
  • Ошибка ключа (KeyError);

Ошибка ключа

Если ключа, к которому нужно получить доступ, не оказывается в словаре, вызывается исключение KeyError.

try:  
    a = {1:'a', 2:'b', 3:'c'}  
    print(a[4])  
except LookupError:  
    print("Исключение KeyError.")
else:  
    print("Успех, нет ошибок!")

Исключение KeyError.

Ошибка индекса

Если пытаться получить доступ к индексу (последовательности) списка, которого не существует в этом списке или находится вне его диапазона, будет вызвана ошибка индекса (IndexError: list index out of range python).

try:
    a = ['a', 'b', 'c']  
    print(a[4])  
except LookupError:  
    print("Исключение IndexError, индекс списка вне диапазона.")
else:  
    print("Успех, нет ошибок!")
Исключение IndexError, индекс списка вне диапазона.

Ошибка памяти (MemoryError)

Как уже упоминалось, ошибка памяти вызывается, когда операции не хватает памяти для выполнения.

Ошибка имени (NameError)

Ошибка имени возникает, когда локальное или глобальное имя не находится.

В следующем примере переменная ans не определена. Результатом будет ошибка NameError.

try:
    print(ans)
except NameError:  
    print("NameError: переменная 'ans' не определена")
else:  
    print("Успех, нет ошибок!")
NameError: переменная 'ans' не определена

Ошибка выполнения (Runtime Error)

Ошибка «NotImplementedError»
Ошибка выполнения служит базовым классом для ошибки NotImplemented. Абстрактные методы определенного пользователем класса вызывают это исключение, когда производные методы перезаписывают оригинальный.

class BaseClass(object):
    """Опередляем класс"""
    def __init__(self):
        super(BaseClass, self).__init__()
    def do_something(self):
	# функция ничего не делает
        raise NotImplementedError(self.__class__.__name__ + '.do_something')

class SubClass(BaseClass):
    """Реализует функцию"""
    def do_something(self):
        # действительно что-то делает
        print(self.__class__.__name__ + ' что-то делает!')

SubClass().do_something()
BaseClass().do_something()

SubClass что-то делает!



---------------------------------------------------------------------------

NotImplementedError                       Traceback (most recent call last)

 in 
     14
     15 SubClass().do_something()
---> 16 BaseClass().do_something()


 in do_something(self)
      5     def do_something(self):
      6         # функция ничего не делает
----> 7         raise NotImplementedError(self.__class__.__name__ + '.do_something')
      8
      9 class SubClass(BaseClass):


NotImplementedError: BaseClass.do_something

Ошибка типа (TypeError)

Ошибка типа вызывается при попытке объединить два несовместимых операнда или объекта.

В примере ниже целое число пытаются добавить к строке, что приводит к ошибке типа.

try:
    a = 5
    b = "PythonRu"
    c = a + b
except TypeError:
    print('Исключение TypeError')
else:
    print('Успех, нет ошибок!')

Исключение TypeError

Ошибка значения (ValueError)

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

В этом примере встроенная операция float получат аргумент, представляющий собой последовательность символов (значение), что является недопустимым значением для типа: число с плавающей точкой.

try:
    print(float('PythonRu'))
except ValueError:
    print('ValueError: не удалось преобразовать строку в float: 'PythonRu'')
else:
    print('Успех, нет ошибок!')
ValueError: не удалось преобразовать строку в float: 'PythonRu'

Пользовательские исключения в Python

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

Это можно сделать, создав новый класс, который будет наследовать из класса Exception в Python.

class UnAcceptedValueError(Exception):   
    def __init__(self, data):    
        self.data = data
    def __str__(self):
        return repr(self.data)

Total_Marks = int(input("Введите общее количество баллов: "))
try:
    Num_of_Sections = int(input("Введите количество разделов: "))
    if(Num_of_Sections < 1):
        raise UnAcceptedValueError("Количество секций не может быть меньше 1")
except UnAcceptedValueError as e:
    print("Полученная ошибка:", e.data)

Введите общее количество баллов: 10
Введите количество разделов: 0
Полученная ошибка: Количество секций не может быть меньше 1

В предыдущем примере если ввести что-либо меньше 1, будет вызвано исключение. Многие стандартные исключения имеют собственные исключения, которые вызываются при возникновении проблем в работе их функций.

Недостатки обработки исключений в Python

У использования исключений есть свои побочные эффекты, как, например, то, что программы с блоками try-except работают медленнее, а количество кода возрастает.

Дальше пример, где модуль Python timeit используется для проверки времени исполнения 2 разных инструкций. В stmt1 для обработки ZeroDivisionError используется try-except, а в stmt2if. Затем они выполняются 10000 раз с переменной a=0. Суть в том, чтобы показать разницу во времени исполнения инструкций. Так, stmt1 с обработкой исключений занимает больше времени чем stmt2, который просто проверяет значение и не делает ничего, если условие не выполнено.

Поэтому стоит ограничить использование обработки исключений в Python и применять его в редких случаях. Например, когда вы не уверены, что будет вводом: целое или число с плавающей точкой, или не уверены, существует ли файл, который нужно открыть.

import timeit
setup="a=0"
stmt1 = '''
try:
    b=10/a
except ZeroDivisionError:
    pass'''

stmt2 = '''
if a!=0:
    b=10/a'''

print("time=",timeit.timeit(stmt1,setup,number=10000))
print("time=",timeit.timeit(stmt2,setup,number=10000))

time= 0.003897680000136461
time= 0.0002797570000439009

Выводы!

Как вы могли увидеть, обработка исключений помогает прервать типичный поток программы с помощью специального механизма, который делает код более отказоустойчивым.

Обработка исключений — один из основных факторов, который делает код готовым к развертыванию. Это простая концепция, построенная всего на 4 блоках: try выискивает исключения, а except их обрабатывает.

Очень важно поупражняться в их использовании, чтобы сделать свой код более отказоустойчивым.

Программа Python будет завершаться при возникновении ошибок, но это не всегда лучший образ действий. Например, мы не хотим, чтобы наш код неожиданно прерывался, когда конечный пользователь с ним работает. Обработка ошибок вносит исправление, которое делает наш код более устойчивым и предотвращает возможные сбои, приводящие к краху нашего приложения.

Различные недостатки всегда будут возникать при программировании. За некоторые проблемы отвечает наш код, например, за синтаксические ошибки. В большинстве случаев такую неточность называют багом. Недостатки должны исправляться.

Даже программа, не имеющая багов, может иметь проблемы, поскольку не все недостатки бывают вызваны кодом. Они могут быть результатом непредусмотренных событий или процедур. Такой тип проблем называется исключениями. Например:

  • Диск может быть заполнен во время записи данных в файлы и препятствовать дальнейшей записи.
  • Неожиданно обрушилась сеть во время загрузки той или иной информации.
  • Использование 0 в знаменателе при делении.

Разница между ошибкой и исключением

Есть два типа ошибок в Python, которые мы должны хорошо понимать. Один тип — это синтаксические ошибки (или ошибки парсинга). При парсинге программы будет обнаружен ошибочный оператор. Ошибки этой природы не могут быть исправлены во время выполнения программы и требуют исправления кода.

Ошибки исключения — еще один тип ошибок, с которыми мы сталкиваемся. Эти ошибки имеют место, когда наш код синтаксически верен, но возникают непредвиденные ситуации при выполнении программы. Они относятся ко времени исполнения и не всегда смертельны. Далее в статье мы сосредоточимся на этих видах ошибок.

Типы ошибок

Синтаксические ошибки

Расположение букв и символов в коде называется синтаксисом. Поэтому, если вы встречаете синтаксическую ошибку, это обычно означает, что в вашем коде пропущен символ или буква. Python будет часто информировать вас о строке и местоположении проблемы. Сообщение об ошибке следует читать очень внимательно.

Блок кода:

num1 = 2
num2 = 3
Num3 = num1 num2
print(num3)

Вывод:

Ошибка нехватки памяти

Если вы получаете сообщение об ошибке памяти, вашему программному обеспечению не хватает памяти. Это говорит о том, что ваше ПО создает слишком много объектов. Memory Error сигнализирует о нехватке доступной памяти для выделения интерпретатором вашему приложению Python. Это может быть проблемой конфигурирования Python или проблемой, связанной с функцией загрузки многих конкурирующих за ресурсы данных.

Ошибка рекурсии

Когда интерпретатор Python при выполнении вашей программы превышает предел рекурсии, возникает исключение Python Recursion Error. Предел рекурсии в Python может быть увеличен, или ваш код может быть переделан, чтобы использовать итерацию, а не рекурсию, чтобы избавиться от этой ошибки.

Блок кода:

def abc():
return abc()
abc()

Вывод:

Ошибка отступа

Python является процедурным языком, поэтому если вы не поместите табулятор или пробелы между строкам вашего кода, то, вероятно, получите ошибку Indentation Error.

Блок кода:

for i in range(3):
print(i)

Вывод:

Что такое обработка исключений в Python?

Вы можете с удобством обслуживать исключения, благодаря встроенной в Python системе обработки исключений. Это механизм try…except…finally.

Все исключения в Python должны быть экземплярами классов, происходящими от Base Exception. Python предлагает разнообразные исключения для часто случающихся ситуаций.

Обычные типы исключений в Python

Ошибка атрибута

Ошибки, связанные со ссылками на атрибуты или присвоением.

Блок кода:

arr = [1,2,3,4,5]
arr.len()

Вывод:

Ошибка индекса

Ошибка возникает, когда индекс последовательности выходит за границы.

Блок кода:

arr = [1,2,3,4,5]
print(arr[200])

Ошибка деления на нуль

Когда целое делится на 0, возникает Zero Division Error.

Блок кода:

arr = 1
arr = 0
print(a/b)

Вывод:

Ошибка типа

Эта ошибка возникает, когда в операции или методе используется объект неправильного типа.

Блок кода:

arr = [1,2,3,4,5]
arr.insert(1)

Вывод:

Ошибка значения

Эта ошибка возникает, когда функция получает аргумент правильного типа, но неверное значение.

Блок кода:

import math
math.sqrt(-33)

Вывод:

Ошибка имени

Эта ошибка возникает, когда идентификатор не находится ни в локальном, ни в глобальном пространстве имен.

Блок кода:

print(Num)

Вывод:

Ошибка ключа

Эта ошибка возникает, когда словарь не включает заданный ключ.

Блок кода:

dic={"name":"achyut","age":20}
print(dic["value"])

Вывод:

Ошибка импорта

Эта ошибка возникает, когда модуль не может быть загружен оператором import.

Блок кода:

from math import add

Вывод:

Предложение Try и оператор Except

Теперь, когда мы вполне осознаем множество дефектов времени выполнения, которые могут привести к нештатному поведению наших программ, мы готовы к решению таких проблем. В Python мы строим блоки try и except для обработки исключений.

Синтаксис

try:
#возможный блок кода, который может вызвать исключение
except Exception:
#Код, который реагирует на возникающую ошибку

Замечание. Один блок try может обрабатывать множество блоков except для различных исключений.

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

Пример

a = input ("enter the Numerator:")
b = input ("enter the Denominator:")
try:
res = int(a) / int(b)
print ('result is:', res)
except ZeroDivisionError as e:
print ('exception is:', e)

Вывод:

Как видно в примере выше, мы можем включить в оператор try часть кода, которая способна вызвать исключение. Блок кода оператора except будет выполняться, если исключения действительно произойдут.

Ошибки могут быть разнообразными. Следует использовать различные блоки except для обработки возникающих ошибок различного вида. Конечно, можно перехватить более одного типа ошибок.

Try с предложением Finally

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

Пример блока Finally

Блок кода:

a = input ("enter the Numerator:")
b = input ("enter the Denominator:")
try:
res = int(a) / int(b)
print ('result is:', res)
except ZeroDivisionError as e:
print ('exception is:', e)
finally:
print ("thank you")

Вывод:

Try с предложением Else

При отсутствии исключений мы можем также приказать программе выполнить код, используя условие else. При отсутствии исключений программа будет выполнять предложение else.

Пример блока Else

Блок кода:

a = input ("enter the Numerator:")
b = input ("enter the Denominator:")
try:
res = int(a) / int(b)
print ('result is:', res)
except ZeroDivisionError as e:
print ('exception is :', e)
else:
print("hello")
finally:
print ("thank you")

Вывод:

Захват конкретных исключений в Python

Как мы уже установили, одинаковая обработка каждой ситуации и захват каждого исключения в предложении except не является хорошей практикой программирования. Следует указывать конкретные исключения, которые будет перехватывать предложение except. Мы можем захватить только встроенное исключение ошибки имени, которое будет обрабатывать исключение, когда пользователь введет некорректное имя.

Пример

Блок кода:

def name_exception():
try:
value = "achyut tripathi"
return xyz
except NameError:
return "NameError occurred"

print(name_exception())

Вывод:

Вызов исключения в Python

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

Пример

Создадим небольшую функцию, которая ожидает число между 1 и 50. Если функция получает значение за пределами этого диапазона, работа приложения будет прервана с помощью пользовательского исключения.

Блок кода:

def range_function(range):
try:
if range > 50 or range <0:
raise Exception()
if range < 100 and range > 0:
print("Range is ok")
except:
print("Exception Occurred")
range_function(150)

Вывод:

Заключение

Примеры в этом руководстве показывают как использовать в Python блок «try-except-finally».

Когда ваш код попадает в производственную среду, обработка ошибок — отличный способ гарантировать, что он ориентирован на будущее. Конечно, юнит-тестирование и реализация ООП также важны. Избегайте слишком большого числа блоков try и except, поскольку это несколько замедлит выполнение вашего кода и в целом его потребуется больше написать. Старайтесь не использовать его, если это не является абсолютно необходимым, например, когда требуется ввод данных пользователем или открывается файл.

#!/usr/bin/python  
str = "this"  
if(1):  
  print "Hi"  
else:  
  print str.any_random_function()  

This doesn’t fail when I run the program. I tried py_compile but that didn’t indicate the error in the else loop either. Now how can I compile the program and detect errors reliably in python code?

ks1322's user avatar

ks1322

33.6k14 gold badges108 silver badges163 bronze badges

asked Jan 22, 2010 at 13:48

stacka's user avatar

3

I think your best bet would be pylint.

answered Jan 22, 2010 at 13:50

Geo's user avatar

GeoGeo

92.8k117 gold badges342 silver badges519 bronze badges

Python is a dynamic language, so you can’t simply check for compiling errors like in static languages (C/C++/Java). If you assign str.any_random_function, the above code would be correct (okay that’s a bad example…).

I’d suggest you to use PyDev for Eclipse which automatically finds many common problems in your code, like missing functions/modules etc. It also supports pylint (optional).

answered Jan 22, 2010 at 13:57

AndiDog's user avatar

AndiDogAndiDog

68.3k21 gold badges159 silver badges205 bronze badges

2

result_str=»»;
for row in range(0,7):
for column in range(0,7):
if (column == 1 or column == 5 or (row == 2 and (column == 2 or column == 4)) or (row == 3 and column == 3)):
result_str=result_str+»* «
else:
result_str=result_str+» «
result_str=result_str+»n»
print(result_str);

answered May 25 at 4:50

Mydhili Chintalapalli's user avatar

4

Уведомления

  • Начало
  • » Python для новичков
  • » Ошибка при компиляции программы в PyScripter

#1 Янв. 10, 2017 14:54:50

Ошибка при компиляции программы в PyScripter

Написал простую программу т.к. только приступил к изучению данного языка. При компиляции вылазит такая ошибка “error ascii codec can’t encode characters in position 32-38 ordinal not in range (128)” Я уже менял кодировку в меню Формат файла, ничего не помогло. Что это и как избавиться от этой ошибки, чтоб программа нормально откомпилировалась?

Отредактировано Lemonade (Янв. 10, 2017 14:56:59)

Офлайн

  • Пожаловаться

#2 Янв. 10, 2017 15:55:03

Ошибка при компиляции программы в PyScripter

код покажите

Влодение рускай арфаграфией — это как владение кунг-фу: настаящие мастира не преминяют ево бес ниабхадимости

Офлайн

  • Пожаловаться

#3 Янв. 10, 2017 16:26:38

Ошибка при компиляции программы в PyScripter

С дураками и сектантами не спорю, истину не ищу.
Ели кому-то правда не нравится, то заранее извиняюсь.

Офлайн

  • Пожаловаться

#4 Янв. 10, 2017 18:53:43

Ошибка при компиляции программы в PyScripter

Вот код. И добавил строку # coding: utf-8, но ничего не изменилось

Прикреплённый файлы:
attachment pythonpic.JPG (45,6 KБ)

Офлайн

  • Пожаловаться

#5 Янв. 10, 2017 19:04:57

Ошибка при компиляции программы в PyScripter

1. В пути к модулю не должно находится ничего кроме латиницы.
2. Имя файла и файлов только латиницей.

Офлайн

  • Пожаловаться

#6 Янв. 10, 2017 19:28:04

Ошибка при компиляции программы в PyScripter

Что вы имеете ввиду? Имя файла, как видно из фото, латиницей. Путь к модулю? Это что, сам файл?
Я выбрал Файл — Новый — Создать модуль, или Файл — Новый — Создать файл — Python скрипт, и так, и так открывается окно, пишу просту программу, только нажимаю кнопку Компиляция, сразу это вылетает.

Офлайн

  • Пожаловаться

#7 Янв. 10, 2017 19:39:43

Ошибка при компиляции программы в PyScripter

Путь к модулю это путь к файлу. Если он будет по пути: c:newпроблема, то будут проблемы. Мало того. У Вас на скрине открыто еще несколько файлов. Уберите их и удалите из папки. Модуль 1 и модуль 2. А лучше прекратите мучить себя и поставьте PyCharm. Бесплатный даже лучше чем PyScripter. Сам на PyScriptere года 4 сидел…

Офлайн

  • Пожаловаться

#8 Янв. 10, 2017 20:26:47

Ошибка при компиляции программы в PyScripter

Это ж я пытался создать файл, чтоб компилировался. Ну странно однако, что ж не так?.. Никто не знает..

Офлайн

  • Пожаловаться

#9 Янв. 10, 2017 20:33:25

Ошибка при компиляции программы в PyScripter

4kpt_IV
А лучше прекратите мучить себя и поставьте PyCharm

Так он мне понравился, т.к легкий, всего 4 мб, а PyCharm 230 мб, зачем зря место на диске занимать.

Отредактировано Lemonade (Янв. 10, 2017 20:34:22)

Офлайн

  • Пожаловаться

#10 Янв. 10, 2017 21:34:28

Ошибка при компиляции программы в PyScripter

Lemonade
PyCharm 230 мб, зачем зря место на диске занимать.

Ну тогда наслаждайтесь глюками.

Lemonade
Это ж я пытался создать файл, чтоб компилировался. Ну странно однако, что ж не так?.. Никто не знает..

Я ответил уже на вопрос. Никто ничего не добавит. Что значит создать? Он его где создает? В виртуальном параллельном мире? Он создает его по пути, который прописан в настройках. Так вот в этом пути не должно быть русских символов. Куда вы установили сам PyScripter и куда Python, с помощью которого он пытается исполнять файл? Где он создает файл? По какому пути? Проверьте все внимательно. Еще были бока у одной версии PyScripter, что он болезненно реагировал на MIME типы в юникоде.

P.S. Ну и он не компилируется, а исполняется. Python — это скриптовый язык.

Офлайн

  • Пожаловаться

  • Начало
  • » Python для новичков
  • » Ошибка при компиляции программы в PyScripter

Понравилась статья? Поделить с друзьями:
  • Ошибка при компиляции ошибка синтаксиса в модуле visual basic
  • Ошибка при компиляции на pawno
  • Ошибка при компиляции undefined reference to
  • Ошибка при компиляции the witcher 3
  • Ошибка при компиляции premiere pro