【问题标题】:Attaching attributes to a class on creation在创建时将属性附加到类
【发布时间】:2012-09-29 09:30:17
【问题描述】:

我有一堆类在 ZODB 中持久化。所有类都必须共享一些索引特性,而且它们都定义了很多属性。这些属性是在类级别上使用描述符定义的,以便能够拦截对它们的写入以进行验证并检查数据库中的重复项。为此,每个类都有一个自动维护的属性列表_properties。他们还拥有_indices 和其他一些功能,我不想自己复制到每个元素类(大约 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 的每一种风格明确指定此集合。

当前的解决方案有效,但我认为它是一个丑陋的 hack,并希望摆脱它。例如。 BaseElement 在其他模块中的子类不会正确设置它们的属性。玩弄__new__ 似乎也是错误的方式,因为它不会拦截类构造,而是拦截实例化。那么,如何正确地做到这一点呢?

附:我知道 OrderedDict,但这不是我要找的。我想以一种干净的方式挂钩到类创建过程并在那里附加任意功能。

【问题讨论】:

标签: python oop class subclassing


【解决方案1】:

您可以使用元类来做到这一点:

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 的每个子类。元类是继承的,因此您只需定义一次。

【讨论】:

  • 正是我需要的,谢谢!多亏了 Blenders 链接,我终于明白了它背后的魔力。
猜你喜欢
  • 1970-01-01
  • 2011-01-11
  • 1970-01-01
  • 1970-01-01
  • 2010-09-19
  • 1970-01-01
  • 2018-04-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多