我有一堆在ZODB中持久化的类。所有类都必须共享一些索引功能,但它们都定义了很多属性。这些属性在类级别上使用描述符定义,以便能够拦截写入它们以进行验证并检查数据库中的重复项。为此,每个类都有一个自动维护属性列表_properties
。他们还拥有_indices
和其他一些功能,我不想自己复制到每个Element-class(大约10个左右)。
请考虑以下代码:
class BaseElement(object):
_properties = None
class ElementFlavour1(BaseElement):
_properties = 'a', 'b', 'c'
....
class ElementFlavourN(BaseElement):
_properties = 'e', 'f', 'g'
for item in locals():
if issubclass(item, BaseElement):
item._v_properties_set = set(item._properties) if item._properties else set()
所以,它基本上做它应该做的事情:我需要线性迭代_properties
,但我也想快速查找,如果类中存在某些属性。尽管如此,我不想重复自己,并明确地为BaseElement
的每一种风格指定这个集合。
当前的解决方案有效,但我认为它是一个丑陋的黑客,并希望摆脱它。例如。其他模块中BaseElement
的子类不会正确设置其属性。玩__new__
也似乎是错误的方式,因为它不拦截类构造,而是实例化。那么,如何正确地做到这一点?
P.S。我知道OrderedDict,但这不是我想要的。我想以干净的方式挂钩类创建过程并在那里添加任意功能。
答案 0 :(得分:4)
你可以用元类来做到这一点:
class BaseType(type):
def __init__(cls, name, bases, clsdict):
super(BaseType, cls).__init__(name, bases, clsdict)
setattr(cls,'_v_properties_set',
set(cls._properties) if cls._properties else set())
class BaseElement(object):
__metaclass__ = BaseType
_properties = None
class ElementFlavour1(BaseElement):
_properties = 'a', 'b', 'c'
class ElementFlavourN(BaseElement):
_properties = 'e', 'f', 'g'
print(ElementFlavourN._v_properties_set)
# set(['e', 'g', 'f'])
您也可以使用类装饰器执行此操作,但是您必须单独装饰BaseElement
的每个子类。元类是继承的,因此您只需要定义一次。