如何动态地向接口添加属性

Gag*_*aro 4 python plone zope.interface

我需要为接口中的每个属性添加一个属性.所以我试图动态修改它来添加它们,但现在还没有取得多大成功.

假设我有以下界面:

class IMember(Interface):
    first_name = schema.TextLine(title=u'first name')
    last_name = schema.TextLine(title=u'last name')
Run Code Online (Sandbox Code Playgroud)

我想像这样修改它:

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')
Run Code Online (Sandbox Code Playgroud)

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

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

那么,有没有办法在Python中完成它,或者我是否必须修改界面并手动添加所有属性?

谢谢 !

Mar*_*ers 6

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

创建其他架构字段的字典:

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

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

from zope.interface.interface import InterfaceClass

IMemberExtended = InterfaceClass('IMemberExtended', (IMember,), fields)
Run Code Online (Sandbox Code Playgroud)

如果您愿意,这可以全部包含在类装饰器中:

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)
Run Code Online (Sandbox Code Playgroud)

您在现有界面上使用的:

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

这创建了一个子类; 你也可以用生成的界面替换整个界面:

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)
Run Code Online (Sandbox Code Playgroud)

最后一个版本的演示:

>>> @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']
Run Code Online (Sandbox Code Playgroud)