如何在 Python 中创建一个行为类似于 Django 抽象基类的类?
Posted
技术标签:
【中文标题】如何在 Python 中创建一个行为类似于 Django 抽象基类的类?【英文标题】:How do I create a class in Python that behaves like Django's abstract base class? 【发布时间】:2011-05-31 07:13:06 【问题描述】:我正在使用现有的 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
【问题讨论】:
name not in ('BaseFoo')
不会像您认为的那样做 - 它会检查 name
是否是 BaseFoo
的子字符串(所以对于 name = 'Foo'
,这将是 False)。要创建一个单例元组,请使用('BaseFoo',)
(注意尾随逗号)——但话说回来,为什么不用name != 'BaseFoo'
?
+1(抵消)为什么要投反对票?这个问题到底有什么问题?
是的,我的代码中有错字。这是混淆代码......原来的版本实际上是name not in ('BaseFoo','OtherBaseFoo')
,但我想简化......哎呀。
@bob 是的,有些人不高兴
【参考方案1】:
无需在具体类中将 abstract 设置为 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 中删除该类,因为它已经在调用装饰器时创建(因此元类已经被调用)。
【讨论】:
+1 不错的解决方案。abstract=False
真的会导致它是抽象的吗?
@kevpie:最初没有,但现在有。以上是关于如何在 Python 中创建一个行为类似于 Django 抽象基类的类?的主要内容,如果未能解决你的问题,请参考以下文章
我想在 iPad 应用程序中创建一个行为类似于操作表的自定义视图
如何在 SQL Server [2005] 中创建类似于 .dbo 的架构