如何在Python中创建类似Django抽象基类的类?
我正在使用一个现有的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中移除,因为在装饰器被调用时,这个类已经创建好了(所以元类也已经被调用过了)。