← Назад к вопросам

За что отвечает finally в блоке try...except

1.6 Junior🔥 211 комментариев
#Python Core

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Finally в блоке try...except

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

Основная структура

try:
    # Код, который может вызвать исключение
    risky_code()
except SomeException:
    # Код, который выполнится если было исключение SomeException
    handle_error()
finally:
    # Код, который ВСЕГДА выполнится
    cleanup()

Все варианты выполнения

print("Начало")

try:
    print("В try блоке")
    # 1. Если ошибки нет
    x = 10 / 2
except ZeroDivisionError:
    print("Ошибка деления на 0")
finally:
    print("Finally выполнится в любом случае")

print("Конец")

# Результат:
# Начало
# В try блоке
# Finally выполнится в любом случае
# Конец

Когда бывает исключение

print("Начало")

try:
    print("В try блоке")
    x = 10 / 0  # ZeroDivisionError!
except ZeroDivisionError:
    print("Ошибка деления на 0")
finally:
    print("Finally выполнится в любом случае")

print("Конец")

# Результат:
# Начало
# В try блоке
# Ошибка деления на 0
# Finally выполнится в любом случае
# Конец

Практический пример: закрытие файла

# БЕЗ finally (неправильно)
def read_file_bad():
    f = open("data.txt", "r")
    try:
        data = f.read()
        # Если здесь ошибка, файл не закроется!
        process(data)
    except Exception:
        pass
    # Файл остаётся открытым

# С finally (правильно)
def read_file_good():
    f = open("data.txt", "r")
    try:
        data = f.read()
        process(data)
    except Exception:
        print("Ошибка при обработке")
    finally:
        f.close()  # Закроется в любом случае

# ИЛИ используй контекстный менеджер (лучше всего)
def read_file_best():
    with open("data.txt", "r") as f:
        data = f.read()
        process(data)
    # Файл автоматически закроется

Работа с ресурсами

import sqlite3

# Неправильно
def bad_db_access():
    conn = sqlite3.connect(":memory:")
    cursor = conn.cursor()
    cursor.execute("SELECT * FROM users")
    # Если ошибка — соединение не закроется

# Правильно с finally
def good_db_access():
    conn = sqlite3.connect(":memory:")
    try:
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM users")
        return cursor.fetchall()
    except Exception as e:
        print(f"Ошибка БД: {e}")
    finally:
        conn.close()  # Всегда закроется

# Лучше всего
def best_db_access():
    with sqlite3.connect(":memory:") as conn:
        cursor = conn.cursor()
        cursor.execute("SELECT * FROM users")
        return cursor.fetchall()
    # Соединение закроется автоматически

Выполнение с return

Finally выполняется даже если в try или except есть return:

def example_with_return():
    try:
        print("1. try блок")
        return "результат из try"
    except Exception:
        print("2. except блок")
    finally:
        print("3. finally выполнится перед return")

result = example_with_return()
print(f"4. результат: {result}")

# Результат:
# 1. try блок
# 3. finally выполнится перед return
# 4. результат: результат из try

Finally с исключением в except

def complex_example():
    try:
        print("1. try")
        x = 1 / 0
    except ZeroDivisionError:
        print("2. except")
        # Даже если нужно выбросить новое исключение
        raise ValueError("Новая ошибка")
    finally:
        print("3. finally выполнится перед тем как выбросится ValueError")

try:
    complex_example()
except ValueError as e:
    print(f"4. Поймано: {e}")

# Результат:
# 1. try
# 2. except
# 3. finally выполнится перед тем как выбросится ValueError
# 4. Поймано: Новая ошибка

Else блок

Можно использовать else, который выполняется только если нет исключения:

try:
    x = 10 / 2
except ZeroDivisionError:
    print("Ошибка")
else:
    print(f"Успех! Результат: {x}")  # Выполнится только если нет ошибки
finally:
    print("Finally всегда")

# Результат:
# Успех! Результат: 5.0
# Finally всегда

Практические применения finally

  1. Закрытие файлов и соединений
  2. Освобождение ресурсов (блокировки, потоки)
  3. Логирование и отчёты
  4. Откат транзакций в БД
import threading

def acquire_resource():
    lock = threading.Lock()
    try:
        lock.acquire()
        # Работа с защищённым ресурсом
        do_something()
    except Exception as e:
        handle_error(e)
    finally:
        lock.release()  # Освободить лок в любом случае

Контекстные менеджеры (лучшая практика)

Вместо finally лучше использовать with (контекстные менеджеры):

# Старый способ
f = open("file.txt")
try:
    data = f.read()
finally:
    f.close()

# Современный способ
with open("file.txt") as f:
    data = f.read()
# Файл закроется автоматически

Итог

  • finally выполняется всегда (даже при return, break, continue)
  • Используй для очистки ресурсов (файлы, соединения, блокировки)
  • Лучше использовать контекстные менеджеры (with) вместо try...finally
  • finally не ловит исключения, а только гарантирует выполнение кода