Python: динамическая подмена класса

Юзкейс

Есть функция-фабрика, возвращающая объект класса A. Функция из сторонней либы, менять ее нельзя (либо вообще ее код закрыт). А нам очень нужно сделать класс B, наследованный от A, и перекрыть magic-метод, скажем __exit__.

Проблема в том, что объекты класса A можно получить только из функции фабрики, а если попытаться переписать метод прямо на существующем объекте, то ничего не выйдет, все равно будет вызван «правильный» метод с класса.

«Наглость- сестра таланта»

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

class B(A):
    def __init__(self):
        pass

    def __new__(cls):
        obj = fabric()
        obj.__class__ = cls
        return obj

    def __enter__(self):
        ...

    def __exit__(self, type, value, tb):
        ...

with B():
    ...

Зачем пустой __init__?

Дело в том, что при вызове фабрики для автоматически вызывается A.__init__(), ведь она создала обычный объект A().
Формально, B() должен был быть совершенно другим объектом, и для него, разумеется, будет вызван B.__init__(), который будет взят от класса A, если не перекрыть. Это приведет к тому, что метод A.__init__() будет вызван дважды!

Может, кому-нибудь пригодится 🙂

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

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *