Поскольку это также недавно меня поразило, я только что подтвердил ответ Майка Пеннингтона с чертами 4.2.1. Похоже, существует различие между изменениями самой черты Списка (такими как присвоение ей нового списка) и изменениями членства Списка (такими как добавление или настройка по индексу). Первый использует то же имя, что и черта (например, inputs
), тогда как второй использует суффикс "_items". Этот пример, кажется, демонстрирует это:
from traits.api import Float, HasTraits, Instance, List
class Part(HasTraits):
costs = List(Float)
# called when the actual List trait changes:
def _costs_changed(self, old, new):
print("Part::_costs_changed %s -> %s" % (str(old), str(new)))
# called when the contents of the List trait changes:
def _costs_items_changed(self, old, new):
print("Part::_costs_changed %s -> %s" % (str(old), str(new)))
class Widget(HasTraits):
part = Instance(Part)
def __init__(self):
self.part = Part()
self.part.on_trait_change(self.update_costs, 'costs')
self.part.on_trait_change(self.update_costs_items, 'costs_items')
def update_costs(self, name, new):
print("update_costs: %s = %s" % (name, str(new),))
def update_costs_items(self, name, new):
print("update_costs_items: %s = %s" % (name, str(new),))
w = Widget()
w.part.costs = [ 1.0, 2.0, 3.0 ]
# Part::_costs_changed [] -> [1.0, 2.0, 3.0]
# update_costs: costs = [1.0, 2.0, 3.0]
w.part.costs = [ 1.0, 2.0, 3.1 ]
# Part::_costs_changed [1.0, 2.0, 3.0] -> [1.0, 2.0, 3.1]
# update_costs: costs = [1.0, 2.0, 3.1]
w.part.costs[0] = 5.0
# Part::_costs_changed <undefined> -> <traits.trait_handlers.TraitListEvent object at 0x1007bd810>
# update_costs_items: costs_items = <traits.trait_handlers.TraitListEvent object at 0x1007bd810>
w.part.costs.append(4.0)
# Part::_costs_changed <undefined> -> <traits.trait_handlers.TraitListEvent object at 0x1007bd810>
# update_costs_items: costs_items = <traits.trait_handlers.TraitListEvent object at 0x1007bd810>
На это поведение намекает документация здесь .
Однако, если используется расширенное имя, кажется, возможно, что тот же обработчик вызывается при изменении всего членства в списке или :
from traits.api import Float, HasTraits, Instance, List
class Part(HasTraits):
costs = List(Float)
def _costs_changed(self, old, new):
print("_costs_changed %s -> %s" % (str(old), str(new)))
def _costs_items_changed(self, old, new):
print("_costs_items_changed %s -> %s" % (str(old), str(new)))
class Widget(HasTraits):
part = Instance(Part)
def __init__(self):
self.part = Part()
self.part.on_trait_change(self.update_costs, 'costs[]') # <-- extended name
def update_costs(self, name, new):
print("update_costs: %s = %s" % (name, str(new),))
w = Widget()
w.part.costs = [ 1.0, 2.0, 3.0 ]
# _costs_changed [] -> [1.0, 2.0, 3.0]
# update_costs: costs = [1.0, 2.0, 3.0]
w.part.costs = [ 1.0, 2.0, 3.1 ]
# _costs_changed [1.0, 2.0, 3.0] -> [1.0, 2.0, 3.1]
# update_costs: costs = [1.0, 2.0, 3.1]
w.part.costs[0] = 5.0
# _costs_items_changed <undefined> -> <traits.trait_handlers.TraitListEvent object at 0x1007c6f90>
# update_costs: costs_items = [5.0]
w.part.costs.append(4.0)
# _costs_items_changed <undefined> -> <traits.trait_handlers.TraitListEvent object at 0x1007c6f90>
# update_costs: costs_items = [4.0]
В этом случае параметр name
обработчика update_costs
можно использовать для различения изменения самого контейнера или изменения одного элемента в контейнере.