Могу ли я запускать код каждый раз, когда абстрактный класс наследуется? - PullRequest
2 голосов
/ 27 июня 2019

Мне нужно подключить сигнал Джанго для всех классов, которые наследуются от абстрактного класса.Существует ли такой магический метод python, как __on_inherit__, который позволял бы мне запускать код подключения сигнала каждый раз, когда мой абстрактный класс наследуется?

Обновление: просто для пояснения мне нужно запускать код оценки класса один раз для каждого класса, а НЕ один раз для экземпляра / объекта.

Ответы [ 3 ]

3 голосов
/ 27 июня 2019

Да, действительно, есть ловушка [__init_subclass__] [1], которая запускается каждый раз, когда класс находится в подклассе.

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

Надеюсь, это поможет вам.

Редактировать : Это было добавлено через PEP 487 [2] в Python версии 3.6. В более ранних версиях Python этот метод не вызывался.

[1] https://docs.python.org/3/reference/datamodel.html#object.init_subclass

[2] https://www.python.org/dev/peps/pep-0487/

2 голосов
/ 27 июня 2019

Для python> = 3.6, __init__subclass__ ok уже упоминается Terseus.

Для более старых версий Python канонический способ подключиться к созданию класса (я имею в виду «создание нового объекта класса») - это использовать собственный метакласс и переопределить либо метод __new__, либо __init__ (это широко распространено). задокументировано, поэтому я не буду публиковать пример).

2 голосов
/ 27 июня 2019

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

def get_descendants(klass):
    gen = { klass }
    desc = set()
    while gen:
        gen = { skls for kls in gen for skls in kls.__subclasses__() }
        desc.update(gen)
    return desc

Далее мы можем повторить это и каждый раз вызывать функцию, например:

for subclass in get_descendants(<i>AbstractModel</i>):
    # ... do something with that subclass
    pass

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

Вы должны инициировать оценку этого при загрузке приложений, например, в методе ready() [Django-doc] из AppConfig.

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

Пример : добавление сигнала к каждому подклассу

Например, мы можем добавить сигнал к каждому подклассу AbstractModel, сначала определив обработчик сигнала:

def test_signal(sender, instance, **kwargs):
    print('{} is saved'.format(instance))

и затем мы можем связать его с каждым подклассом:

from django.db.models.signals import <b>post_save</b>

for subclass in get_descendants(<i>AbstractModel</i>):
    <b>post_save.connect(</b>test_signal, sender=subclass<b>)</b>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...