Что такое monkey patching в Python

Ответ

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

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

Основные сценарии использования:

  • Тестирование: Замена внешних зависимостей (например, сетевых запросов или работы с базой данных) на mock-объекты. Библиотека unittest.mock.patch активно использует этот механизм.
  • Исправление багов: Временное исправление ошибок в сторонней библиотеке до выхода официального патча.
  • Добавление функциональности: Расширение возможностей существующего класса.

Пример:

import datetime

# Сохраняем оригинальный метод
_original_datetime_now = datetime.datetime.now

def patched_now():
    # Всегда возвращаем фиксированную дату
    return datetime.datetime(2023, 1, 1, 12, 0, 0)

# Применяем monkey patch
datetime.datetime.now = patched_now

# Теперь любой вызов datetime.datetime.now() вернет нашу дату
print(f"Текущее время после патча: {datetime.datetime.now()}")
# Вывод: Текущее время после патча: 2023-01-01 12:00:00

# Возвращаем оригинальное поведение (важно для чистоты кода)
datetime.datetime.now = _original_datetime_now

Ответ 18+ 🔞

О, слушай, вот эта штука — monkey patching, ну, как обезьяна с гаечным ключом под капотом, блядь. Суть в том, что ты можешь на лету, прямо во время работы программы, хуяк — и подменить методы или атрибуты у классов и модулей. То есть, не лезешь в исходники, не переписываешь библиотеку, а просто, внаглую, впендюриваешь своё.

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

Ну и где это, блядь, применяют?

  • Тестирование, сука. Самый частый случай. Нужно, чтобы какой-нибудь запрос в интернет не ходил, а возвращал тестовые данные. Берешь и подменяешь эту функцию на свою заглушку. Библиотека unittest.mock.patch — это она и есть, просто в красивом фраке.
  • Исправление косяков. Нашел баг в чужой библиотеке, а фикс выйдет только через месяц. Ну, ты не ждешь, как лох, а пишешь временный патч и вманиваешь его, чтобы твой код не падал.
  • Добавление фич. Хочется, чтобы у стандартного класса была ещё какая-то приблуда. Просто добавляешь ему новый метод, и все, ты — царь и бог этого класса.

Смотри, как это выглядит на практике:

import datetime

# Сохраняем оригинальный метод на всякий пожарный, а то потом не найдёшь
_original_datetime_now = datetime.datetime.now

def patched_now():
    # А тут мы, хитрая жопа, всегда будем возвращать одну и ту же дату
    return datetime.datetime(2023, 1, 1, 12, 0, 0)

# ВАУ! Магия! Подменяем стандартный метод на наш
datetime.datetime.now = patched_now

# Теперь любой вызов datetime.datetime.now() вернёт нашу фиктивную дату
print(f"Текущее время после патча: {datetime.datetime.now()}")
# Вывод: Текущее время после патча: 2023-01-01 12:00:00

# И главное, блядь, не забудь вернуть как было, особенно в тестах!
datetime.datetime.now = _original_datetime_now

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