2

我想包装一个非特征模型类以与 Python 特征一起使用。我的目标是编写一个基于 Traits 的 UI 来操作“外部”模型类。外部模型类已由 SWIG 生成,因此我无法将 enthought.traits.api.HasTraits 添加为祖先(我认为,尽管我可能错了)。

我目前最好的尝试是

from enthought.traits.api import HasStrictTraits, Property, Instance

class ExternalModel():
    foo = 'foo'

class TraitsModel(HasStrictTraits):
    _e = Instance(ExternalModel)

    def __init__(self):
        self._e = ExternalModel()
        self.add_trait('foo', Property(lambda     :getattr(self._e,'foo'     ),
                                       lambda attr:setattr(self._e,'foo',attr)))

这导致基于 Traits 的类 TraitsModel 具有一个可变属性,该属性委托给包含的非 Traits ExternalModel 实例。但是, TraitsModel.trait_names() 不会将 'foo' 报告为可识别的特征。

关于如何让 TraitsModel 报告与 ExternalModel 相关联的“foo”特征的任何建议?enthought.traits.api.DelegatesTo 似乎要求目标是 Traits 类(尽管我可能没有找到正确的调用,这是可能的)。

一种更类似于 MVC 的方法可能是对我的 ExternalModel 有一个基于 Traits 的视图。我一直无法弄清楚基于特征的视图有一个非特征模型。这方面的建议也非常受欢迎。

更新我已经弄清楚如何使用http://agentzlerich.blogspot.com/2011_05_01_archive.html上的方法将 HasTraits 作为 ExternalModel 超类,这似乎完全是浪费时间。显然 SWIG voodoo 和 Traits 不祥之物不存在。按照这个问题的要求,在 TraitsModel 中包装 ExternalModel 似乎是最好的方法。

4

1 回答 1

2
from enthought.traits.api import HasStrictTraits, Instance, Property

class ExternalModel(object):
    foo = 'foo'

class TraitsModel(HasStrictTraits):
    _e = Instance(ExternalModel, ExternalModel())

    def __init__(self):
        '''
        >>> wrapper = TraitsModel()
        >>> wrapper.foo
        'foo'
        >>> wrapper._e.foo = 'bar'
        >>> wrapper.foo
        'bar'
        >>> wrapper.trait_names()
        ['trait_added', '_e', 'foo', 'trait_modified']
        '''
        HasStrictTraits.__init__(self)
        for trait in (name for name in dir(self._e) if not name.startswith('__')):
            self.__class__.add_class_trait(
                trait,
                Property(
                    lambda:getattr(self._e, trait),
                    lambda attr:setattr(self._e, trait, attr)
                )
            )


if __name__ == '__main__':
    import doctest
    doctest.testmod()

一个相当健壮的解决方案是使用类add_class_traitHasTraits,加上dir(self._e)获取属性的名称ExternalModel和生成器表达式/列表理解来过滤魔术类方法名称(filter使用适当的函数可以更好地包装更复杂的班级)。

还:

  • ExternalModel应该继承自object

  • __init__应该调用HasStrictTraits.__init__(或super(HasStrictTraits, self).__init__()

  • _e也可以在 Instance trait 声明中使用ExternalModel()or even作为第二个参数创建(),或者作为 TraitsModel 的方法,例如:

    def __e_default(self): # note preceding underscore
        return ExternalModel()
    

最后,我有一份略旧的 Enthought API 副本,其中包括非常方便的 Traits。

于 2011-06-18T12:47:28.730 回答