4

我需要为界面中的每个属性添加一个属性。所以我正在尝试动态修改它以添加它们,但目前没有太大成功。

假设我有以下界面:

class IMember(Interface):
    first_name = schema.TextLine(title=u'first name')
    last_name = schema.TextLine(title=u'last name')

我想这样修改它:

class IMember(Interface):
    first_name = schema.TextLine(title=u'first name')
    last_name = schema.TextLine(title=u'last name')
    visbility_first_name = schema.Bool(title=u'Display: first name')
    visbility_last_name = schema.Bool(title=u'Display: last name')

之后我尝试修改该类,但由于它已经初始化,因此设置了架构,我不知道如何更改它。我还考虑过编写一个指令(例如:interface.Implements()),但仅仅添加属性似乎相当复杂。

我的最终目标是添加一个带有一组 Bool 小部件的 z3c.form 字段集。

那么,有没有办法在 Python 中做到这一点,还是我必须修改界面并手动添加所有属性?

谢谢 !

4

2 回答 2

6

您可以使用元类型创建接口的动态子类InterfaceClass

创建附加模式字段的字典:

fields = {}
for name, attr in IMember.namesAndDescriptions():
    if isinstance(attr, schema.Field):
        fields['visible_' + name] = schema.Bool(title=u'Display: ' + attr.title)

现在您可以创建一个动态接口子类化现有接口:

from zope.interface.interface import InterfaceClass

IMemberExtended = InterfaceClass('IMemberExtended', (IMember,), fields)

如果您愿意,这一切都可以包含在类装饰器中:

from zope.interface.interface import InterfaceClass
from zope import schema

def add_visibility_fields(iface):            
    fields = {}
    for name, attr in iface.namesAndDescriptions():
        if isinstance(attr, schema.Field):
            fields['visible_' + name] = schema.Bool(title=u'Display: ' + attr.title)

    return InterfaceClass(iface.__name__, (iface,), fields)

您将在现有界面上使用:

@add_visibility_fields
class IMember(Interface):
    first_name = schema.TextLine(title=u'first name')
    last_name = schema.TextLine(title=u'last name')

这将创建一个子类;您还可以将整个界面替换为生成的界面:

def add_visibility_fields(iface):            
    fields = {}
    for name, attr in iface.namesAndDescriptions():
        fields[name] = attr
        if isinstance(attr, schema.Field):
            fields['visible_' + name] = schema.Bool(title=u'Display: ' + attr.title)

    return InterfaceClass(iface.__name__, iface.__bases__, fields)

最后一个版本的演示:

>>> @add_visibility_fields
... class IMember(Interface):
...     first_name = schema.TextLine(title=u'first name')
...     last_name = schema.TextLine(title=u'last name')
... 
>>> IMember.names()
['visible_last_name', 'first_name', 'last_name', 'visible_first_name']
于 2013-08-08T15:40:15.400 回答
0

似乎您想使用 python 的元类。使用自定义元类将允许您修改类的创建,因此您可以在创建类时/之前动态添加或修改属性。有关元类的出色 SO 答案,请参阅这篇文章

但是,您应该尝试重新构建程序以避免必须使用元类。通常,只有在您确实知道需要它们时才应使用它们。在您的情况下,是否可以修改schema.TextLine以允许您想要的行为(也许通过添加一个钩子)?

于 2013-08-08T15:14:26.057 回答