2011-12-03 10 views
6

私はtraitspresentation from PyCon 2010で作業しています。約2:30:45で、発表者はをカバーし始めます。traitが変更されたときはいつでもサブルーチンを自動的に呼び出すことができます。Traits静的イベント通知をリストに表示するにはどうすればよいですか?

私は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" 

私はこのスクリプトを実行すると、私はので、私は、私はspinal_tap.volume11.0を割り当てるとき_volume_changed()が解雇されることを知って、コンソール出力にThis one goes to eleven... so far, we have seen [5.0, 11.0]を見ることができます。

しかし、私は_inputs_changed()からのイベントは見ません。どのような例で私が調理しても、私はListイベントを発生させることができません。

これは私が見ている出力です... _inputs_changed()が今までに発生するという証拠はないことに注意してください。

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

私は(すべてが、私は直接Enthought's siteオフeasy_installtraitsバージョン4.0.0を使用して)両方のpython2.6/Cygwinの/ Windows 7のとPython 2.5/Linuxでこれを実行しました。これまでに何を試しても、結果は同じです。

Listは、形質を使用するときに静的イベントを発生させることができますか?もしそうなら、私は何か間違っているのですか?

答えて

5

自分のユニットテストを閲覧した後、私はあなたがこのような魔法のイベントリスナーメソッドを設定する必要がありDictまたはList状の容器を持っている場合、それがどのように見える... enthoughtのevent unittest coverageDict形質のテストが見つかりました:

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

は同様に、私はまた、あなたがtraits.api.Listtraits.api.Dictでそれを呼び出している場合(ダイナミックtraitsイベント通知のために使用される)on_trait_changeデコレータは、同様の命名法を必要とする...私はまた、上記のようなコードを書くことができることを発見しました:

私は、コードを実行したとき
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 

いずれかの方法では、私が期待される出力を得る:これはまた、最近私を捕まえたよう

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

を、私はちょうど上の特徴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> 

この動作は、ドキュメントhereで示唆されています。この場合

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パラメータ:extended名前が使用されている場合

しかし、全体のリストまたはメンバーシップが変更されたときに呼び出される同じハンドラを持つことが可能思えんupdate_costsハンドラを使用すると、コンテナ自体を変更したり、コンテナ内の単一の項目を変更したりすることができます。

+0

この情報をお寄せいただきありがとうございます。 –

関連する問題