如何在Python中创建类似Django抽象基类的类?

2 投票
1 回答
655 浏览
提问于 2025-04-16 09:05

我正在使用一个现有的Django库,并且我想创建一个抽象类。

假设这个类叫做 BaseFoo

目前,这个实现有一个基础类 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

在具体类中不需要把抽象设置为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装饰器中把这个类从class_list中移除,因为在装饰器被调用时,这个类已经创建好了(所以元类也已经被调用过了)。

撰写回答