如何将非Traits模型封装以便与Python Traits一起使用?
我想把一个不是Traits模型的类包装起来,以便可以和Python的Traits一起使用。我的目标是写一个基于Traits的用户界面,用来操作一个“外部”的模型类。这个外部模型类是通过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的视图。我一直没能弄明白如何让一个非Traits模型为基于Traits的视图服务。对此方向的建议也非常欢迎。
更新 我已经找到了如何让HasTraits作为ExternalModel的父类,使用的方法可以在http://agentzlerich.blogspot.com/2011_05_01_archive.html找到,但这似乎完全是浪费时间。显然,SWIG的魔法和Traits的魔法并不兼容。根据这个问题的要求,把ExternalModel包装在TraitsModel中似乎是最好的办法。
1 个回答
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_trait
这个方法,它属于 HasTraits
类。同时,可以用 dir(self._e)
来获取 ExternalModel
类的属性名称,再结合生成器表达式或列表推导式来过滤掉那些特殊的类方法名(如果你需要处理更复杂的类,使用 filter
和合适的函数会更好)。
另外:
ExternalModel
应该继承自object
__init__
方法应该调用HasStrictTraits.__init__
(或者用super(HasStrictTraits, self).__init__()
)_e
也可以在实例特性声明中作为第二个参数创建,使用ExternalModel()
或者直接用()
,或者作为TraitsModel
的一个方法,像这样:def __e_default(self): # note preceding underscore return ExternalModel()
最后,我有一个 稍微旧一点的 Enthought API 包括 Traits,这可能会很有用。