以下是shell失败的示例。
>>> from traits.api import Dict
>>> d=Dict()
>>> d['Foo']='BAR'
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: 'Dict' object does not support item assignment
我一直在网上搜索,并没有指示如何使用Dict。
我正在尝试编写一个显示python字典内容的简单应用程序。这个链接(Defining view elements from dictionary elements in TraitsUI)是适度有用的,除了字典在某个poll_interval上更新,如果我在那里使用解决方案(在从HasTraits派生的类中包装一个普通的python dict),显示不会更新基础词典得到更新。
以下是我现在所拥有的相关部分。最后一个类几乎可以被忽略,我包含它的唯一原因是帮助理解我打算如何使用Dict。
pyNetObjDisplay.run_ext()从基类run()方法每次循环调用一次
class DictContainer(HasTraits):
_dict = {}
def __getattr__(self, key):
return self._dict[key]
def __getitem__(self, key):
return self._dict[key]
def __setitem__(self, key, value):
self._dict[key] = value
def __delitem__(self, key, value):
del self._dict[key]
def __str__(self):
return self._dict.__str__()
def __repr__(self):
return self._dict.__repr__()
def has_key(self, key):
return self._dict.has_key(key)
class displayWindow(HasTraits):
_remote_data = Instance(DictContainer)
_messages = Str('', desc='Field to display messages to the user.', label='Messages', multi_line=True)
def __remote_data_default(self):
tempDict = DictContainer()
tempDict._dict = Dict
#tempDict['FOO'] = 'BAR'
sys.stderr.write('SETTING DEFAULT DICTIONARY:\t%s\n' % tempDict)
return tempDict
def __messages_default(self):
tempStr = Str()
tempStr = ''
return tempStr
def traits_view(self):
return View(
Item('object._remote_data', editor=ValueEditor()),
Item('object._messages'),
resizable=True
)
class pyNetObjDisplay(pyNetObject.pyNetObjPubClient):
'''A derived pyNetObjPubClient that stores remote data in a dictionary and displays it using traitsui.'''
def __init__(self, hostname='localhost', port=54322, service='pyNetObject', poll_int=10.0):
self._display = displayWindow()
self.poll_int = poll_int
super(pyNetObjDisplay, self).__init__(hostname, port, service)
self._ui_running = False
self._ui_pid = 0
### For Testing Only, REMOVE THESE LINES ###
self.connect()
self.ns_subscribe(service, 'FOO', poll_int)
self.ns_subscribe(service, 'BAR', poll_int)
self.ns_subscribe(service, 'BAZ', poll_int)
############################################
def run_ext(self):
if not self._ui_running:
self._ui_running = True
self._ui_pid = os.fork()
if not self._ui_pid:
time.sleep(1.25*self.poll_int)
self._display.configure_traits()
for ((service, namespace, key), value) in self._object_buffer:
sys.stderr.write('TEST:\t' + str(self._display._remote_data) + '\n')
if not self._display._remote_data.has_key(service):
self._display._remote_data[service] = {}
if not self._display._remote_data[service].has_key(namespace):
#self._remote_data[service][namespace] = {}
self._display._remote_data[service][namespace] = {}
self._display._remote_data[service][namespace][key] = value
msg = 'Got Published ((service, namespace, key), value) pair:\t((%s, %s, %s), %s)\n' % (service, namespace, key, value)
sys.stderr.write(msg)
self._display._messages += msg
sys.stderr.write('REMOTE DATA:\n' + str(self._display._remote_data)
self._object_buffer = []
答案 0 :(得分:1)
我认为你的基本问题与生活在模型对象之外的特征的通知问题有关,而不是与“如何访问这些对象”本身有关[编辑:实际上这根本不是你的问题!但是,当我以我对以前遇到的问题的偏见心态阅读你的问题时,我认为你试图做的事情,无论如何我建议的解决方案仍然有效]。我最近遇到了这类问题,因为我决定如何设计我的程序(代码描述了一个GUI,它模块化地分离了它可以包含的非常复杂的数据集)。您可能已经找到了我的其他问题,因为您找到了第一个问题。
在远离GUI的复杂数据层次结构中存在大量数据并不是traitsui为您的应用程序考虑的设计,它会导致通知的各种问题。设计解决方案具有更扁平的设计,其中GUI信息更直接地集成到程序的不同部分中。
我认为通常可以使用各种变通方法(我在enabled_when listening outside model object中使用了一些不涉及字典的方法)。我不确定对你的词典问题最有设计友好的解决方案是什么,但有一件事是有效的并且不会干扰你的设计(但它仍然是一个“有点烦人”的解决方案)是让一切都在字典是HasTraits,因此将其标记为可听。像这样:
from traits.api import *
from traitsui.api import *
from traitsui.ui_editors.array_view_editor import ArrayViewEditor
import numpy as np
class DContainer(HasTraits):
_dict=Dict
def __getattr__(self, k):
if k in self._dict:
return self._dict[k]
class DItem(HasTraits):
_item=Any
def __init__(self,item):
super(DItem,self).__init__()
self._item=item
def setitem(self,val):
self._item=val
def getitem(self):
return self._item
def traits_view(self):
return View(Item('_item',editor=ArrayViewEditor()))
class LargeApplication(HasTraits):
d=Instance(DContainer)
stupid_listener=Any
bn=Button('CLICKME')
def _d_default(self):
d=DContainer()
d._dict={'a_stat':DItem(np.random.random((10,1))),
'b_stat':DItem(np.random.random((10,10)))}
return d
def traits_view(self):
v=View(
Item('object.d.a_stat',editor=InstanceEditor(),style='custom'),
Item('bn'),
height=500,width=500)
return v
def _bn_fired(self):
self.d.a_stat.setitem(np.random.random((10,1)))
LargeApplication().configure_traits()
答案 1 :(得分:0)
好的,我在这个问题中找到了答案(kindof):Traits List not reporting items added or removed
当将Dict或List对象作为属性包含在类中时,不应该这样做:
class Foo(HasTraits):
def __init__(self):
### This will not work as expected!
self.bar = Dict(desc='Description.', label='Name', value={})
而是这样做:
class Foo(HasTraits):
def __init__(self):
self.add_trait('bar', Dict(desc='Description.', label='Name', value={}) )
现在以下内容将起作用:
>>> f = Foo()
>>> f.bar['baz']='boo'
>>> f.bar['baz']
'boo'
不幸的是,由于某种原因,使用configure_traits()生成的GUI在基础数据更改时不会更新它的视图。以下是一些演示此问题的测试代码:
import os
import time
import sys
from traits.api import HasTraits, Str, Dict
from traitsui.api import View, Item, ValueEditor
class displayWindow(HasTraits):
def __init__(self, **traits):
super(displayWindow, self).__init__(**traits)
self.add_trait('_remote_data', Dict(desc='Dictionary to store remote data in.', label='Data', value={}) )
self.add_trait('_messages', Str(desc='Field to display messages to the user.', label='Messages', multi_line=True, value='') )
def traits_view(self):
return View(
Item('object._remote_data', editor=ValueEditor()),
Item('object._messages'),
resizable=True
)
class testObj(object):
def __init__(self):
super(testObj, self).__init__()
self._display = displayWindow()
self._ui_pid = 0
def run(self):
### Run the GUI in the background
self._ui_pid = os.fork()
if not self._ui_pid:
self._display.configure_traits()
i = 0
while True:
self._display._remote_data[str(i)] = i
msg = 'Added (key,value):\t("%s", %s)\n' % (str(i), i, )
self._display._messages += msg
sys.stderr.write(msg)
time.sleep(5.0)
i+=1
if __name__ == '__main__':
f = testObj()
f.run()