Как мне создать класс в Python, который ведет себя как абстрактный базовый класс Джанго? - PullRequest
2 голосов
/ 27 декабря 2010

Я использую существующую библиотеку Django и создаю класс, который хотел бы быть абстрактным.

Допустим, речь идет о BaseFoo.

В настоящее время реализация имеет базовый класс BaseFoo.

Каждый раз, когда создается класс, расширяющий BaseFoo, метакласс добавляет его в список классов.Он явно не добавляет BaseFoo, выполняя жестко запрограммированный тест для имени класса:

    if name not in ('BaseFoo',):
        class_list.append(new_cls)

Я бы хотел написать что-то вроде:

class MyBaseFoo(BaseFoo):
    class Meta:
        abstract = True

И пусть метакласс пропустит все BaseFoo абстрактные объекты.Поэтому я думаю, мне интересно, как Django делает то же самое с моделями и существует ли простой и элегантный способ сделать это самостоятельно.

Я просмотрел код, используемый Django для определения моделей, ноЯ мог бы использовать несколько указателей.Также, если есть еще более простой способ сделать это без необходимости использования class Meta, я тоже открыт для этого.

Обратите внимание, что я не особенно взволнован этим решением:

class MyBaseFoo(BaseFoo):
    abstract = True

class ActualFoo1(MyBaseFoo):
    abstract = False

class ActualFoo2(MyBaseFoo):
    abstract = False

1 Ответ

3 голосов
/ 27 декабря 2010

Нет необходимости устанавливать абстрактное значение False в конкретных классах - достаточно иметь этот параметр только в абстрактных классах:

class_list = []
class CollectSubclasses(type):
    def __new__(cls, name, bases, attrs):
        abstract = False
        if attrs.get('abstract', False):
            abstract = True
            del attrs['abstract']
        res = super(CollectSubclasses, cls).__new__(cls, name, bases, attrs)
        if not abstract:
            class_list.append(res)
        return res

class BaseFoo(object):
    __metaclass__ = CollectSubclasses
    abstract = True

class Concrete1(BaseFoo):
    pass

class Abstract(BaseFoo):
    abstract = True

class Concrete2(Abstract):
    pass

print class_list

Альтернативой могут быть декораторы классов в Python 2.6, однако выпотребуется удалить класс из списка классов в декораторе @abstract, поскольку он уже был создан при вызове декоратора (и, следовательно, метакласс уже был вызван).

...