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

时间:2013-08-08 15:05:47

标签: python plone zope.interface

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

假设我有以下界面:

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中完成,或者我是否必须修改界面并手动添加所有属性?

谢谢!

2 个答案:

答案 0 :(得分: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']

答案 1 :(得分:0)

好像你想使用python的元类。使用自定义元类将允许您修改类的创建,因此您可以在创建类之前/之前动态添加或修改属性。有关元类的优秀SO答案,请参阅this post

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