2013-08-08 2 views
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()), но представляется довольно сложным сделать только для добавления атрибутов.

Моя конечная цель - добавить набор полей z3c.form с набором виджетов Bool.

Итак, есть ли способ сделать это на Python, или мне нужно изменить интерфейс и добавить все атрибуты вручную?

Спасибо!

+0

Вы уверены, что ваши дополнительные атрибуты должны быть первые поля класса на схеме? Возможно, [Tagged Values] (https://developer.plone.org/components/interfaces.html#tagged-values) на интерфейсе может работать для вас. –

+0

Извините, на мобильных устройствах возникли проблемы с отправкой правильных ссылок: http://docs.zope.org/zope.interface/README.html # tagged-values ​​ –

+0

Моя конечная цель - иметь набор полей в z3c.form с набором виджетов Bool. Я не думаю, что отмеченные значения будут полезны в этом случае. – Gagaro

ответ

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'] 
0

Похоже, вы хотите использовать метаклассы python. Использование настраиваемого метакласса позволит вам изменить создание класса, чтобы вы могли динамически добавлять или изменять атрибуты при создании класса до его создания. Для отличного ответа SO на метаклассах см. this post.

Однако вы должны попробовать и реструктурировать свою программу, чтобы избежать использования метаклассов. Обычно они должны использоваться только , если вы действительно знаете, что в них нуждаетесь. В вашем случае можно ли изменить schema.TextLine, чтобы позволить вам поведение (возможно, добавив крючок)?

+0

'zope.interface' уже сильно использует метаклассы, хотя это будет ... сложно интегрироваться с этим. –

+0

Да, использовать метаклассы сложно, но я даже не могу себе представить, какая часть головной боли, пытающаяся сделать наследование метакласса, должна быть ... Тем более разумно найти решение, которое их не привлекает! – FastTurtle

+0

Да, это кажется довольно сложным в реализации, имея более легкое решение было бы здорово :). – Gagaro

Смежные вопросы