Как я могу отправить уведомление о статическом событии Traits в Список?

Я работаю через traits презентация от PyCon 2010. Около 2:30:45 докладчик начинает освещать уведомления о событиях, которые позволяют (помимо прочего) автоматически вызывать подпрограмму в любое время. trait изменился

Я запускаю измененную копию примера, который он дал... В этом испытании я пытаюсь выяснить, могу ли я запускать статическое событие всякий раз, когда я изменяю volume или же inputs,

from traits.api import HasTraits, Range, List, Float
import traits
class Amplifier(HasTraits):
    """
    Define an Amplifier (a la Spinal Tap) with Enthought's traits.  Use traits  
    to enforce values boundaries on the Amplifier's objects.  Use events to 
    notify via the console when the volume trait is changed and when new volume 
    traits are added to inputs.
    """
    volume = Range(value=5.0, trait=Float, low=0.0, high=11.0)
    inputs = List(volume)    # I want to fire a static trait event notification
                             # when another volume element is added

    def __init__(self, volume=5.0):
        super(Amplifier, self).__init__()
        self.volume = volume
        self.inputs.append(volume)

    def _volume_changed(self, old, new):
        # static event listener for self.volume
        if not (new in self.inputs):
            self.inputs.append(self.volume)
        if new == 11.0:
            print "This one goes to eleven... so far, we have seen", self.inputs

    def _inputs_changed(self, old, new):
        # static event listener for self.inputs
        print "Check it out!!"

if __name__=='__main__':
    spinal_tap = Amplifier()
    spinal_tap.volume = 11.0
    print "DIRECTLY adding a new volume input..."
    spinal_tap.inputs.append(4.0)
    try:
        print "NEGATIVE Test... adding 12.0"
        spinal_tap.inputs.append(12.0)
    except  traits.trait_errors.TraitError:
        print "Test passed"

Когда я запускаю этот скрипт, я вижу This one goes to eleven... so far, we have seen [5.0, 11.0] в выводе консоли, так что я знаю, что _volume_changed() увольняют, когда я назначаю 11.0 в spinal_tap.volume,

Тем не менее, я никогда не вижу событий от _inputs_changed(), Независимо от того, какой пример я готовлю, я не могу получить List провести событие.

Это вывод, который я вижу... обратите внимание, что нет никаких доказательств того, что _inputs_changed() когда-либо пожары.

[mpenning@Bucksnort ~]$ python spinaltap.py
This one goes to eleven... so far, we have seen [5.0, 11.0]
DIRECTLY adding a new volume input...
NEGATIVE Test... adding 12.0
Test passed
[mpenning@Bucksnort ~]$

Я запустил это как под Python2.6 / Cygwin / Windows 7 и Python 2.5 / Linux (все с использованием traits версия 4.0.0, которую я easy_install прямо с сайта Enthought). Результаты одинаковы, независимо от того, что я пробовал до сих пор.

Должен ли List быть в состоянии вызвать статическое событие при использовании черт? Если так, я делаю что-то не так?

2 ответа

Решение

Просмотрев их модульные тесты, я нашел тест для Dict черты в освещении событий блока Enthought... это выглядит, когда у вас есть контейнер, как Dict или же List что вам нужно настроить метод прослушивания магических событий, например так:

## Broken method definition: def _inputs_changed(self, old, new):
# container event static listeners must be in the form of _foo_items_changed()
def _inputs_items_changed(self, old, new):
    # static event listener for self.inputs
    if len(new.added) > 0:
        print "Check it out, we added %s to self.items" % new.added
    elif len(new.removed) > 0:
        print "Check it out, we removed %s from self.items" % new.removed

Кроме того, я также обнаружил, что on_trait_change декоратор (используется для динамического traits уведомление о событии) требует аналогичной номенклатуры, если вы вызываете его с traits.api.List или же traits.api.Dict... так что я мог бы также написать код выше, как:

from traits.api import on_trait_change
# ...
@on_trait_change('inputs_items')
def something_changed(self, name, new):
    # static event listener for self.inputs
    if len(new.added) > 0:
        print "Check it out, we added %s to self.items" % new.added
    elif len(new.removed) > 0:
        print "Check it out, we removed %s from self.items" % new.removed

В любом случае, когда я запускаю код, я получаю ожидаемый результат:

[mpenning@Bucksnort ~]$ python spinaltap.py
Check it out, we added [5.0] to self.items
Check it out, we added [11.0] to self.items
This one goes to eleven... so far, we have seen [5.0, 11.0]
DIRECTLY adding a new volume input...
Check it out, we added [4.0] to self.items
NEGATIVE Test... adding 12.0
Test passed
[mpenning@Bucksnort ~]$

Так как это также недавно меня поразило, я только что подтвердил ответ Майка Пеннингтона с чертами 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 Обработчик может использоваться для различения изменения самого контейнера или изменения одного элемента в контейнере.

Другие вопросы по тегам