Except: примеры (PYTHON)

Исключения в Python: перехват и управление ошибками
Раздел: Операторы, Обработка исключений
except(exception_type: Exception = BaseException, variable: str = None)

Основа исключений в Python

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

Базовый синтаксис блока выглядит следующим образом:

try:
    # Код, который может вызвать исключение
    ...
except [ТипИсключения] [as идентификатор]:
    # Код для обработки исключения
    ...
[except [ТипИсключения2] [as идентификатор]:
    ...]
[else:
    # Код, выполняемый при отсутствии исключений]
[finally:
    # Код, выполняемый всегда]

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

Аргументы и возвращаемые значения

Ключевое слово except может использоваться с различными параметрами:

  1. except: Перехватывает все исключения, возникшие в блоке try. Использование без указания конкретного типа считается плохой практикой, так как скрывает системные ошибки (например, KeyboardInterrupt).
  2. except ТипИсключения: Перехватывает исключения указанного типа и всех его подклассов. Например, except ValueError перехватит ValueError и любые его наследники.
  3. except ТипИсключения as e: Перехватывает исключение и сохраняет объект исключения в переменной e. Это позволяет получить доступ к атрибутам исключения (например, e.args) или вывести информацию о нем (print(e)).
  4. except (ТипИсключения1, ТипИсключения2): Перехватывает несколько различных типов исключений в одном блоке, используя кортеж.

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

Базовые примеры использования

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

Перехват всех исключений

try:
    result = 10 / 0
except:
    print("Произошла какая-то ошибка.")
Произошла какая-то ошибка.

Перехват конкретного исключения

try:
    num = int("не число")
except ValueError as e:
    print(f"Ошибка преобразования: {e}")
Ошибка преобразования: invalid literal for int() with base 10: 'не число'

Перехват нескольких исключений отдельными блоками

try:
    # Может вызвать либо ValueError, либо ZeroDivisionError
    x = int(input("Введите число: "))
    y = 10 / x
    print(f"Результат: {y}")
except ValueError:
    print("Введено некорректное число.")
except ZeroDivisionError:
    print("Деление на ноль невозможно.")
Введите число: 0
Деление на ноль невозможно.

Перехват нескольких исключений одним блоком

try:
    my_list = [1, 2, 3]
    value = my_list[5]  # IndexError
except (IndexError, KeyError) as e:
    print(f"Ошибка доступа к элементу коллекции: {type(e).__name__}")
Ошибка доступа к элементу коллекции: IndexError

Использование else и finally

try:
    file = open("example.txt", "r")
except FileNotFoundError:
    print("Файл не найден.")
else:
    content = file.read()
    print("Файл успешно прочитан.")
    file.close()
finally:
    print("Блок finally выполнен в любом случае.")
Файл не найден.
Блок finally выполнен в любом случае.

Похожие конструкции в Python

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

  • finally: Блок кода, который выполняется всегда, независимо от того, возникло исключение или нет. Он используется для освобождения ресурсов (закрытие файлов, сетевых соединений). Основное отличие от except - код в finally выполняется в любом случае, даже если в блоке except было вызвано новое исключение или использован оператор return.
  • else (в контексте try): Блок, который выполняется только если в блоке try не было выброшено ни одного исключения. Позволяет отделить код, который может вызвать исключение, от кода, который должен работать только при успешном выполнении первого. Это улучшает читаемость и помогает избежать случайного перехвата исключений, которые не должны были быть обработаны в данном блоке except.

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

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

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

Java

try {
    int result = 10 / 0;
} catch (ArithmeticException e) {
    System.out.println("Деление на ноль: " + e.getMessage());
} finally {
    System.out.println("Блок finally");
}
Деление на ноль: / by zero
Блок finally

Особенности: Строгая типизация исключений (проверяемые и непроверяемые), несколько блоков catch.

JavaScript

try {
    JSON.parse("invalid json");
} catch (error) {
    console.log("Ошибка парсинга:", error.name);
} finally {
    console.log("Завершение обработки");
}
Ошибка парсинга: SyntaxError
Завершение обработки

Особенности: Один блок catch для всех типов ошибок, объект ошибки имеет свойства name и message.

C#

try
{
    int[] arr = new int[5];
    int x = arr[10];
}
catch (IndexOutOfRangeException ex)
{
    Console.WriteLine($"Индекс за пределами: {ex.Message}");
}
catch (Exception ex)
{
    Console.WriteLine($"Другая ошибка: {ex.Message}");
}
Индекс за пределами: Index was outside the bounds of the array.

Особенности: Похож на Java, есть блок catch для конкретных исключений и общий. Используется фильтрация исключений с помощью when.

PHP

try {
    $result = 10 / 0;
} catch (DivisionByZeroError $e) {
    echo "Перехвачена ошибка: " . $e->getMessage();
} finally {
    echo "\nБлок finally";
}
Перехвачена ошибка: Division by zero
Блок finally

Особенности: До PHP 8.0 ошибки деления на ноль были предупреждениями, а не исключениями. Механика try-catch-finally аналогична Python.

Golang

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

f, err := os.Open("filename.txt")
if err != nil {
    log.Fatal(err) // Обработка ошибки
}
defer f.Close() // Аналог finally

Особенности: Явная проверка ошибок после каждого вызова. defer гарантирует выполнение функции при выходе из текущей.

Типичные ошибки при использовании

Некоторые распространенные проблемы при работе с конструкцией try...except.

Слишком широкий перехват исключений

try:
    user_input = input("Введите что-нибудь: ")
    # ... какой-то код ...
except:
    print("Ошибка!")

Такая конструкция перехватит даже KeyboardInterrupt (Ctrl+C) и SystemExit, что может помешать корректному завершению программы. Лучше указывать конкретные типы исключений.

Неправильный порядок блоков except

try:
    value = int("abc")
except Exception:  # Этот блок перехватит ВСЕ исключения, включая ValueError
    print("Общая ошибка")
except ValueError: # Этот блок никогда не выполнится!
    print("Ошибка значения")
Общая ошибка

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

Потеря исходного исключения

try:
    1 / 0
except ZeroDivisionError:
    raise ValueError("Случилось деление на ноль") # Трассировка начнется отсюда

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

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

try:
    config = load_config("config.yaml")
except FileNotFoundError:
    pass  # Тихая ошибка, которую сложно отладить

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

История изменений

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

Можно отметить эволюцию связанных возможностей:

  • Python 3.3: Введен синтаксис raise ... from для явного указания причинной связи между исключениями, что улучшает читаемость цепочек исключений (chained exceptions).
  • Python 3.11: Значительно улучшена читаемость и информативность трассировок стека (traceback). Появилась возможность добавлять примечания к исключениям с помощью метода add_note(). Хотя это не меняет сам блок except, но влияет на процесс отладки исключений.

Таким образом, базовый принцип работы except сохраняется, обеспечивая обратную совместимость.

Расширенные примеры и техники

Более сложные и специализированные варианты применения обработки исключений.

Повторный выброс исключения

Пример python
def process_data(data):
    try:
        return complex_parsing(data)
    except ValueError:
        print("Не удалось разобрать данные на низком уровне.")
        raise  # Исключение передается выше по стеку вызовов

try:
    process_data("corrupted")
except ValueError:
    print("Ошибка обработана на верхнем уровне.")
Не удалось разобрать данные на низком уровне.
Ошибка обработана на верхнем уровне.

Создание цепочек исключений (raise from)

Пример python
try:
    config = open("config.json")
except OSError as e:
    raise RuntimeError("Не удалось загрузить конфигурацию") from e
RuntimeError: Не удалось загрузить конфигурацию

В трассировке будет указано, что RuntimeError было вызвано непосредственно из-за OSError.

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

Пример python
def read_numbers_from_file(filename):
    try:
        with open(filename) as f:
            for line in f:
                yield int(line.strip())
    except (FileNotFoundError, ValueError) as e:
        print(f"Проблема при чтении файла: {e}")
        yield None  # Или использовать return для остановки

for num in read_numbers_from_file("data.txt"):
    if num is None:
        break
    print(num * 2)

Использование else для оптимизации

Пример python
def get_value_from_cache_or_calculate(key):
    cache = {}
    try:
        value = cache[key]
    except KeyError:
        print("Значение не в кэше, вычисляем...")
        value = expensive_calculation(key)
        cache[key] = value
    else:
        print("Значение найдено в кэше.")
    return value

Блок else здесь выполняется только при успешном извлечении из кэша, что делает намерения разработчика более ясными.

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

Пример python
data_sources = ["source1.csv", "source2.csv", "broken.csv", "source4.csv"]
results = []
for source in data_sources:
    try:
        data = load_csv(source)
        results.append(data)
    except FileNotFoundError:
        print(f"Файл {source} не найден, пропускаем.")
    except csv.Error:
        print(f"Ошибка формата в {source}, пропускаем.")
print(f"Успешно загружено {len(results)} файлов.")
Файл broken.csv не найден, пропускаем.
Успешно загружено 3 файлов.

Кастомизированная обработка с проверкой условия

Пример python
class NetworkError(Exception):
    def __init__(self, message, code):
        super().__init__(message)
        self.code = code

try:
    response = make_http_request(url)
except NetworkError as e:
    if e.code == 404:
        print("Ресурс не найден.")
    elif e.code == 500:
        print("Ошибка сервера.")
    else:
        print(f"Неизвестная сетевая ошибка: {e.code}")

питон except function comments

En
Except Catch an exception in a try block