Wie kann ich eine Merkmal der statischen Ereignisbenachrichtigung auf einer Liste abfeuern?

StackOverflow https://stackoverflow.com/questions/8371980

Frage

Ich arbeite durch die traits Präsentation von Pycon 2010. Gegen 2:30:45 beginnt der Moderator abzudecken Benachrichtigungen über Merkmale, die unter anderem die Fähigkeit erlauben, ein Unterprogramm automatisch zu nennen, jederzeit a trait hat sich verändert.

Ich führe eine modifizierte Kopie des Beispiels durch, das er gegeben hat ... In diesem Prozess versuche ich zu sehen, ob ich ein statisches Ereignis abfeuern kann, wenn ich eine Änderung vornehme volume oder 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"

Wenn ich dieses Skript ausführe, kann ich sehen This one goes to eleven... so far, we have seen [5.0, 11.0] in der Konsolenausgabe, also weiß ich das _volume_changed() wird abgefeuert, wenn ich zuweise 11.0 zu spinal_tap.volume.

Ich sehe jedoch nie Ereignisse von _inputs_changed(). Egal welches Beispiel ich koche, ich kann keine bekommen List ein Ereignis zu entlassen.

Dies ist die Ausgabe, die ich sehe ... Beachten Sie, dass es keine Beweise dafür gibt _inputs_changed() jemals Feuer.

[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 ~]$

Ich habe dies sowohl unter python2.6 / cygwin / windows 7 als auch unter python 2.5 / linux (alle verwendet traits Version 4.0.0, dass ich easy_install direkt aus Auf der Seite von begeistert). Die Ergebnisse sind gleich, egal was ich bisher versucht habe.

Sollte a List in der Lage sein, ein statisches Ereignis zu entlassen, wenn sie Eigenschaften verwenden? Wenn ja, mache ich etwas falsch?

War es hilfreich?

Lösung

Nach dem Durchsuchen ihrer Unit -Tests fand ich einen Test für Dict Merkmale bei begeisterten Event Unittest Berichterstattung... es sieht so aus, als wenn Sie einen Container wie ein haben Dict oder List Dass Sie die Magic Event -Listener -Methode wie folgt einrichten müssen:

## 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

Ebenso entdeckte ich auch, dass das on_trait_change Dekorateur (verwendet für die Dynamik traits Ereignisbenachrichtigung) erfordert eine ähnliche Nomenklatur, wenn Sie sie mit einem anrufen traits.api.List oder traits.api.Dict... damit ich den obigen Code auch schreiben konnte wie:

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

Wenn ich den Code ausführe, werde ich in jedem Fall die erwartete Ausgabe:

[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 ~]$

Andere Tipps

Da mich dies auch in letzter Zeit erwischt habe, habe ich die Antwort von Mike Pennington mit Merkmalen 4.2.1 überprüft. Es scheint eine Unterscheidung zwischen Änderungen des List -Merkmals selbst (z. B. der Zuweisung einer neuen Liste) und Änderungen an der Mitgliedschaft der Liste (z. B. Anhang oder Einstellung nach Index). Ersteres verwendet den gleichen Namen wie das Merkmal (z. B. zB inputs), während letzteres das Suffix "_Items" verwendet. Dieses Beispiel scheint dies zu demonstrieren:

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>

Dieses Verhalten wird in der Dokumentation angedeutet hier.

Jedoch wenn an erweitert Name wird verwendet, es scheint möglich, die zu haben gleich Handler rief an, als die gesamte Liste oder Mitgliedschaft wird geändert:

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]

In diesem Fall die name Parameter der update_costs Der Handler kann verwendet werden, um zwischen dem änderenden Container selbst oder einem einzelnen Element innerhalb des Containers zu differenzieren.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top