Как вы получаете доступ к словарю под traits.api.Dict()?
Вот пример отказа от оболочки.
>>> 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. Эта ссылка ( определение элементов представления из элементов словаря в TraitsUI) была в меру полезной, за исключением того факта, что словарь обновляется для некоторого poll_interval, и если я использую там решение (оборачивая обычный python dict в класс, производный от HasTraits), отображение делает не обновляется, когда базовый словарь обновляется.
Вот соответствующие части того, что я имею прямо сейчас. Последний класс можно в значительной степени игнорировать, единственная причина, по которой я его включил, - это помочь понять, как я собираюсь использовать 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 = []
2 ответа
Я думаю, что ваша основная проблема связана с проблемами уведомлений для признаков, которые живут вне объекта модели, а не с "как получить доступ к этим объектам" как таковым [править: на самом деле нет, это не ваша проблема вообще! Но это то, что, как я думал, вы пытались сделать, когда я прочитал ваш вопрос с моим предвзятым отношением к проблемам, с которыми я сталкивался ранее, и в любом случае предложенное мной решение все равно будет работать]. Недавно я столкнулся с такой проблемой из-за того, как я решил спроектировать свою программу (с кодом, описывающим графический интерфейс, отделенным модульно от очень сложных наборов данных, которые он может содержать). Возможно, вы нашли мои другие вопросы, как вы нашли первый.
Наличие большого количества данных в сложной иерархии данных вне ГИП - это не тот дизайн, который задумал traitsui для вашего приложения, и он вызывает всевозможные проблемы с уведомлениями. Проектирование должно иметь более плоский дизайн, в котором информация графического интерфейса пользователя более непосредственно интегрирована в различные части вашей программы.
Я думаю, что в общем случае для этого могут быть возможны различные обходные пути (некоторые из них я использовал, например, в enabled_when при прослушивании вне объекта модели), которые не включают словари. Я не уверен, что наиболее подходящим для решения вашей проблемы со словарями является дизайн, но одна вещь, которая работает и не сильно мешает вашему дизайну (но это все еще "несколько раздражающее" решение), это сделать все в словарь должен быть 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()
Хорошо, я нашел ответ (kindof) в этом вопросе: список черт, не сообщающий элементы, добавленные или удаленные
при включении объектов 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(), не обновляет свой вид при изменении базовых данных. Вот некоторый тестовый код, который демонстрирует проблему:
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()