1.. _on-trait-change-notification:
2
3===========================================
4Trait Notification with **on_trait_change**
5===========================================
6
7**on_trait_change** is an older method for setting up change notifications. It
8has several design flaws and limitations. A newer mechanism **observe** is
9introduced for overcoming them. See :ref:`observe-notification` for details and
10for how to migrate.
11
12Change notifications can be set up with **on_trait_change** in several ways:
13
14.. index:: notification; strategies
15
16* Dynamically, by calling on_trait_change() or on_trait_event() to establish
17  (or remove) change notification handlers.
18* Statically, by decorating methods on the class with the @on_trait_change
19  decorator to indicate that they handle notification for specified attributes.
20* Statically, by using a special naming convention for methods on the class to
21  indicate that they handle notifications for specific trait attributes.
22
23.. index:: notification; dynamic
24
25.. _dynamic-notification:
26
27Dynamic Notification
28--------------------
29
30Dynamic notification is useful in cases where a notification handler cannot be
31defined on the class (or a subclass) whose trait attribute changes are to be
32monitored, or if you want to monitor changes on certain instances of a class,
33but not all of them. To use dynamic notification, you define a handler method
34or function, and then invoke the on_trait_change() or on_trait_event() method
35to register that handler with the object being monitored. Multiple handlers can
36be defined for the same object, or even for the same trait attribute on the
37same object. The handler registration methods have the following signatures:
38
39.. index:: on_trait_change; method
40
41.. method:: on_trait_change(handler[, name=None, remove=False, dispatch='same'])
42
43.. index:: on_trait_event(); method
44
45.. method:: on_trait_event(handler[, name=None, remove=False, dispatch='same'])
46
47In these signatures:
48
49* *handler*: Specifies the function or bound method to be called whenever the
50  trait attributes specified by the *name* parameter are modified.
51* *name*: Specifies trait attributes whose changes trigger the handler being
52  called. If this parameter is omitted or is None, the handler is called
53  whenever *any* trait attribute of the object is modified. The syntax
54  supported by this parameter is discussed in :ref:`the-name-parameter`.
55* *remove*: If True (or non-zero), then handler will no longer be called when
56  the specified trait attributes are modified. In other words, it causes the
57  handler to be "unhooked".
58* *dispatch*: String indicating the thread on which notifications must be run.
59  In most cases, it can be omitted. See the *Traits API Reference* for details
60  on non-default values.
61
62.. index:: examples; dynamic notification
63
64.. _example-of-a-dynamic-notification-handler:
65
66Example of a Dynamic Notification Handler
67`````````````````````````````````````````
68
69Setting up a dynamic trait attribute change notification handler is illustrated
70in the following example::
71
72    # dynamic_notification.py --- Example of dynamic notification
73    from traits.api import Float, HasTraits, Instance
74
75    class Part (HasTraits):
76      cost = Float(0.0)
77
78    class Widget (HasTraits):
79      part1 = Instance(Part)
80      part2 = Instance(Part)
81      cost  = Float(0.0)
82
83      def __init__(self):
84        self.part1 = Part()
85        self.part2 = Part()
86        self.part1.on_trait_change(self.update_cost, 'cost')
87        self.part2.on_trait_change(self.update_cost, 'cost')
88
89      def update_cost(self):
90        self.cost = self.part1.cost + self.part2.cost
91
92    # Example:
93    w = Widget()
94    w.part1.cost = 2.25
95    w.part2.cost = 5.31
96    print w.cost
97    # Result: 7.56
98
99In this example, the Widget constructor sets up a dynamic trait attribute
100change notification so that its update_cost() method is called whenever the
101**cost** attribute of either its **part1** or **part2** attribute is modified.
102This method then updates the cost attribute of the widget object.
103
104.. index:: name parameter; on_trait_change()
105
106.. _the-name-parameter:
107
108The *name* Parameter
109````````````````````
110
111The *name* parameter of on_trait_change() and on_trait_event() provides
112significant flexibility in specifying the name or names of one or more trait
113attributes that the handler applies to. It supports syntax for specifying
114names of trait attributes not just directly on the current object, but also
115on sub-objects referenced by the current object.
116
117The *name* parameter can take any of the following values:
118
119* Omitted, None, or 'anytrait': The handler applies to any trait attribute on
120  the object.
121* A name or list of names: The handler applies to each trait attribute on the
122  object with the specified names.
123* An "extended" name or list of extended names: The handler applies to each
124  trait attribute that matches the specified extended names.
125
126.. index::
127   pair: extended trait names; syntax
128
129.. _syntax:
130
131Syntax
132::::::
133
134Extended names use the following syntax:
135
136.. productionList::
137   xname: xname2['.'xname2]*
138   xname2: ( xname3 | '['xname3[','xname3]*']' ) ['*']
139   xname3: xname | ['+'|'-'][name] | name['?' | ('+'|'-')[name]]
140
141A *name* is any valid Python attribute name.
142
143.. index::
144   pair: extended trait names; semantics
145
146.. _semantics:
147
148Semantics
149:::::::::
150
151.. _semantics-of-extended-name-notation-table:
152
153.. rubric:: Semantics of extended name notation
154
155+------------------------------+----------------------------------------------+
156| Pattern                      | Meaning                                      |
157+==============================+==============================================+
158|*item1*\ .\ *item2*           |A trait named item1 contains an object (or    |
159|                              |objects, if *item1* is a list or dictionary), |
160|                              |with a trait named *item2*. Changes to either |
161|                              |*item1* or *item2* trigger a  notification.   |
162+------------------------------+----------------------------------------------+
163|*item1*\ :*item2*             |A trait named **item1** contains an object (or|
164|                              |objects, if *item1* is a list or dictionary), |
165|                              |with a trait named *item2*. Changes to *item2*|
166|                              |trigger a notification, while changes to      |
167|                              |*item1* do not (i.e., the ':' indicates that  |
168|                              |changes to the link object are not reported.  |
169+------------------------------+----------------------------------------------+
170|[*item1*, *item2*, ...,       |A list that matches any of the specified      |
171|*itemN*]                      |items. Note that at the topmost level, the    |
172|                              |surrounding square brackets are optional.     |
173+------------------------------+----------------------------------------------+
174|*item*\ []                    |A trait named *item* is a list. Changes to    |
175|                              |*item* or to its members triggers a           |
176|                              |notification.                                 |
177+------------------------------+----------------------------------------------+
178|*name*?                       |If the current object does not have an        |
179|                              |attribute called *name*, the reference can be |
180|                              |ignored. If the '?' character is omitted, the |
181|                              |current object must have a trait called       |
182|                              |*name*; otherwise, an exception is raised.    |
183+------------------------------+----------------------------------------------+
184|*prefix*\ +                   |Matches any trait attribute on the object     |
185|                              |whose name begins with *prefix*.              |
186+------------------------------+----------------------------------------------+
187|+\ *metadata_name*            |Matches any trait on the object that has a    |
188|                              |metadata attribute called *metadata_name*.    |
189+------------------------------+----------------------------------------------+
190|-*metadata_name*              |Matches any trait on the current object that  |
191|                              |does *not* have a metadata attribute called   |
192|                              |*metadata_name*.                              |
193+------------------------------+----------------------------------------------+
194|*prefix*\ +\ *metadata_name*  |Matches any trait on the object whose name    |
195|                              |begins with *prefix* and that has a metadata  |
196|                              |attribute called *metadata_name*.             |
197+------------------------------+----------------------------------------------+
198|*prefix*\ -*metadata_name*    |Matches any trait on the object whose name    |
199|                              |begins with *prefix* and that does *not* have |
200|                              |a metadata attribute called *metadata_name*.  |
201+------------------------------+----------------------------------------------+
202|``+``                         |Matches all traits on the object.             |
203+------------------------------+----------------------------------------------+
204|*pattern*\ *                  |Matches object graphs where *pattern* occurs  |
205|                              |one or more times. This option is useful for  |
206|                              |setting up listeners on recursive data        |
207|                              |structures like trees or linked lists.        |
208+------------------------------+----------------------------------------------+
209
210.. index:: extended trait names; examples
211
212.. _examples-of-extended-name-notation-table:
213
214.. rubric:: Examples of extended name notation
215
216+--------------------------+--------------------------------------------------+
217|Example                   | Meaning                                          |
218+==========================+==================================================+
219|``'foo, bar, baz'``       |Matches *object*.\ **foo**, *object*.\ **bar**,   |
220|                          |and *object*.\ **baz**.                           |
221+--------------------------+--------------------------------------------------+
222|``['foo', 'bar', 'baz']`` |Equivalent to ``'foo, bar, baz'``, but may be     |
223|                          |useful in cases where the individual items are    |
224|                          |computed.                                         |
225+--------------------------+--------------------------------------------------+
226|``'foo.bar.baz'``         |Matches *object*.\ **foo.bar.baz**                |
227+--------------------------+--------------------------------------------------+
228|``'foo.[bar,baz]'``       |Matches *object*.\ **foo.bar** and                |
229|                          |*object*.\ **foo.baz**                            |
230+--------------------------+--------------------------------------------------+
231|``'foo[]'``               |Matches a list trait on *object* named **foo**.   |
232+--------------------------+--------------------------------------------------+
233|``'([left,right]).name*'``|Matches the **name** trait of each tree node      |
234|                          |object that is linked from the **left** or        |
235|                          |**right** traits of a parent node, starting with  |
236|                          |the current object as the root node. This pattern |
237|                          |also matches the **name** trait of the current    |
238|                          |object, as the **left** and **right** modifiers   |
239|                          |are optional.                                     |
240+--------------------------+--------------------------------------------------+
241|``'+dirty'``              |Matches any trait on the current object that has a|
242|                          |metadata attribute named **dirty** set.           |
243+--------------------------+--------------------------------------------------+
244|``'foo.+dirty'``          |Matches any trait on *object*.\ **foo** that has a|
245|                          |metadata attribute named **dirty** set.           |
246+--------------------------+--------------------------------------------------+
247|``'foo.[bar,-dirty]'``    |Matches *object*.\ **foo.bar** or any trait on    |
248|                          |*object*.\ **foo** that does not have a metadata  |
249|                          |attribute named **dirty** set.                    |
250+--------------------------+--------------------------------------------------+
251
252For a pattern that references multiple objects, any of the intermediate
253(non-final) links can be traits of type Instance, List, or Dict. In the case of
254List or Dict traits, the subsequent portion of the pattern is applied to each
255item in the list or value in the dictionary. For example, if **self.children**
256is a list, a handler set for ``'children.name'`` listens for changes to the
257**name** trait for each item in the **self.children** list.
258
259.. note::
260    In the case of Dict, List, and Set with nested patterns (e.g.,
261    ``'children.name'``), not all handler signatures (see
262    :ref:`notification-handler-signatures`) are supported; see section
263    :ref:`dynamic-handler-special-cases` for more details.
264
265The handler routine is also invoked when items are added or removed from a list
266or dictionary, because this is treated as an implied change to the item's trait
267being monitored.
268
269.. index:: notification; dynamic
270
271.. _notification-handler-signatures:
272
273Notification Handler Signatures
274```````````````````````````````
275
276The handler passed to on_trait_change() or on_trait_event() can have any one of
277the following signatures:
278
279.. index:: handler; signatures, trait change handler; signatures
280
281- handler()
282- handler(*new*)
283- handler(*name*, *new*)
284- handler(*object*, *name*, *new*)
285- handler(*object*, *name*, *old*, *new*)
286
287These signatures use the following parameters:
288
289.. index:: object parameter; notification handlers
290
291* *object*: The object whose trait attribute changed.
292
293.. index:: name parameter; notification handlers
294
295* *name*: The attribute that changed. If one of the objects in a sequence is a
296  List or Dict, and its membership changes, then this is the name of the trait
297  that references it, with '_items appended. For example, if the handler is
298  monitoring ``'foo.bar.baz'``, where **bar** is a List, and an item is added
299  to **bar**, then the value of the *name* parameter is 'bar_items'.
300
301.. index:: new parameter to the notification handlers
302
303* *new*: The new value of the trait attribute that changed. For changes to
304  List and Dict objects, this is a list of items that were added.
305
306.. index:: old parameter to the notification handlers
307
308* *old*: The old value of the trait attribute that changed. For changes to List
309  and Dict object, this is a list of items that were deleted. For event traits,
310  this is Undefined.
311
312If the handler is a bound method, it also implicitly has *self* as a first
313argument.
314
315.. index:: notification; special cases
316
317.. _dynamic-handler-special-cases:
318
319Dynamic Handler Special Cases
320`````````````````````````````
321
322In the one- and two-parameter signatures, the handler does not receive enough
323information to distinguish between a change to the final trait attribute being
324monitored, and a change to an intermediate object. In this case, the
325notification dispatcher attempts to map a change to an intermediate object to
326its effective change on the final trait attribute. This mapping is only
327possible if all the intermediate objects are single values (such as Instance or
328Any traits), and not List or Dict traits. If the change involves a List or
329Dict, then the notification dispatcher raises a TraitError when attempting to
330call a one- or two-parameter handler function, because it cannot unambiguously
331resolve the effective value for the final trait attribute.
332
333Zero-parameter signature handlers receive special treatment if the final trait
334attribute is a List or Dict, and if the string used for the *name* parameter is
335not just a simple trait name. In this case, the handler is automatically called
336when the membership of a final List or Dict trait is changed. This behavior can
337be useful in cases where the handler needs to know only that some aspect of the
338final trait has changed. For all other signatures, the handler function must be
339explicitly set for the *name*\ _items trait in order to called when the
340membership of the name trait changes. (Note that the *prefix*\ + and *item*\ []
341syntaxes are both ways to specify both a trait name and its '_items' variant.)
342
343This behavior for zero-parameter handlers is not triggered for simple trait
344names, to preserve compatibility with code written for versions of Traits
345prior to 3.0. Earlier versions of Traits required handlers to be separately
346set for a trait and its items, which would result in redundant notifications
347under the Traits 3.0 behavior. Earlier versions also did not support the
348extended trait name syntax, accepting only simple trait names. Therefore, to
349use the "new style" behavior of zero-parameter handlers, be sure to include
350some aspect of the extended trait name syntax in the name specifier.
351
352.. index:: examples; handlers
353
354::
355
356    # list_notifier.py -- Example of zero-parameter handlers for an object
357    #                     containing a list
358    from traits.api import HasTraits, List
359
360    class Employee: pass
361
362    class Department( HasTraits ):
363        employees = List(Employee)
364
365    def a_handler(): print("A handler")
366    def b_handler(): print("B handler")
367    def c_handler(): print("C handler")
368
369    fred = Employee()
370    mary = Employee()
371    donna = Employee()
372
373    dept = Department(employees=[fred, mary])
374
375    # "Old style" name syntax
376    # a_handler is called only if the list is replaced:
377    dept.on_trait_change( a_handler, 'employees' )
378    # b_handler is called if the membership of the list changes:
379    dept.on_trait_change( b_handler, 'employees_items')
380
381    # "New style" name syntax
382    # c_handler is called if 'employees' or its membership change:
383    dept.on_trait_change( c_handler, 'employees[]' )
384
385    print("Changing list items")
386    dept.employees[1] = donna     # Calls B and C
387    print("Replacing list")
388    dept.employees = [donna]      # Calls A and C
389
390.. index:: notification; static
391
392.. _static-notification:
393
394Static Notification
395-------------------
396
397The static approach is the most convenient option, but it is not always
398possible. Writing a static change notification handler requires that, for a
399class whose trait attribute changes you are interested in, you write a method
400on that class (or a subclass).  Therefore, you must know in advance what
401classes and attributes you want notification for, and you must be the author
402of those classes. Static notification also entails that every instance of the
403class has the same notification handlers.
404
405To indicate that a particular method is a static notification handler for a
406particular trait, you have two options:
407
408.. index::
409   pair: decorator; on_trait_change
410
411* Apply the @on_trait_change decorator to the method.
412* Give the method a special name based on the name of the trait attribute it
413  "listens" to.
414
415.. _handler-decorator:
416
417Handler Decorator
418`````````````````
419The most flexible method of statically specifying that a method is a
420notification handler for a trait is to use the @on_trait_change() decorator.
421The @on_trait_change() decorator is more flexible than specially-named method
422handlers, because it supports the very powerful extended trait name syntax
423(see :ref:`the-name-parameter`). You can use the decorator to set handlers on
424multiple attributes at once, on trait attributes of linked objects, and on
425attributes that are selected based on trait metadata.
426
427.. index::
428   pair: on_trait_change; syntax
429
430.. _decorator-syntax:
431
432Decorator Syntax
433::::::::::::::::
434
435The syntax for the decorator is::
436
437    @on_trait_change( 'extended_trait_name' )
438    def any_method_name( self, ...):
439    ...
440
441In this case, *extended_trait_name* is a specifier for one or more trait
442attributes, using the syntax described in :ref:`the-name-parameter`.
443
444The signatures that are recognized for "decorated" handlers are the same as
445those for dynamic notification handlers, as described in
446:ref:`notification-handler-signatures`. That is, they can have an *object*
447parameter, because they can handle notifications for trait attributes that do
448not belong to the same object.
449
450.. index::
451   pair: on_trait_change; semantics
452
453.. _decorator-semantics:
454
455Decorator Semantics
456:::::::::::::::::::
457
458The functionality provided by the @on_trait_change() decorator is identical to
459that of specially-named handlers, in that both result in a call to
460on_trait_change() to register the method as a notification handler. However,
461the two approaches differ in when the call is made. Specially-named handlers
462are registered at class construction time; decorated handlers are registered at
463instance creation time.
464
465By default, decorated handlers are registered prior to setting the object
466state. When an instance is constructed with a trait value that is different
467from the default, that is considered a change and will fire the associated
468change handlers. The ``post_init`` argument in @on_trait_change can be used
469to delay registering the handler to after the state is set.
470
471.. literalinclude:: /../../examples/tutorials/doc_examples/examples/post_init_notification.py
472   :start-after: post_init_notification
473
474.. index:: notification; specially-named handlers
475
476.. _specially-named-notification-handlers:
477
478Specially-named Notification Handlers
479`````````````````````````````````````
480
481There are two kinds of special method names that can be used for static trait
482attribute change notifications. One is attribute-specific, and the other
483applies to all trait attributes on a class.
484
485.. index:: _name_changed(), _name_fired()
486
487To notify about changes to a single trait attribute named name, define a method
488named _\ *name*\ _changed() or _\ *name*\ _fired(). The leading underscore
489indicates that attribute-specific notification handlers are normally part of a
490class's private API. Methods named _\ *name*\ _fired() are normally used with
491traits that are events, described in :ref:`trait-events`.
492
493To notify about changes to any trait attribute on a class, define a method
494named _anytrait_changed().
495
496.. index::
497   pair: examples; _anytrait_changed()
498   pair: static notification; examples
499
500Both of these types of static trait attribute notification methods are
501illustrated in the following example::
502
503    # static_notification.py --- Example of static attribute
504    #                            notification
505    from traits.api import HasTraits, Float
506
507    class Person(HasTraits):
508        weight_kg = Float(0.0)
509        height_m =  Float(1.0)
510        bmi = Float(0.0)
511
512        def _weight_kg_changed(self, old, new):
513             print('weight_kg changed from %s to %s ' % (old, new))
514             if self.height_m != 0.0:
515                 self.bmi = self.weight_kg / (self.height_m**2)
516
517        def _anytrait_changed(self, name, old, new):
518             print('The %s trait changed from %s to %s ' \
519                    % (name, old, new))
520    """
521    >>> bob = Person()
522    >>> bob.height_m = 1.75
523    The height_m trait changed from 1.0 to 1.75
524    >>> bob.weight_kg = 100.0
525    The weight_kg trait changed from 0.0 to 100.0
526    weight_kg changed from 0.0 to 100.0
527    The bmi trait changed from 0.0 to 32.6530612245
528    """
529
530In this example, the attribute-specific notification function is
531_weight_kg_changed(), which is called only when the **weight_kg** attribute
532changes. The class-specific notification handler is _anytrait_changed(), and
533is called when **weight_kg**, **height_m**, or **bmi** changes. Thus, both
534handlers are called when the **weight_kg** attribute changes. Also, the
535_weight_kg_changed() function modifies the **bmi** attribute, which causes
536_anytrait_changed() to be called for that attribute.
537
538The arguments that are passed to the trait attribute change notification
539method depend on the method signature and on which type of static notification
540handler it is.
541
542.. note::
543    The :func:`~.on_trait_change` and :func:`~.observe` decorators nullify
544    the effect of special naming. A method that looks like::
545
546        @observe("foo")
547        def _foo_changed(self, event):
548            do_something_with(event)
549
550    will only be called once when ``foo`` changes, as a result of the
551    ``observe`` decorator.
552
553.. _attribute-specific-handler-signatures:
554
555Attribute-specific Handler Signatures
556`````````````````````````````````````
557
558For an attribute specific notification handler, the method signatures supported
559are:
560
561.. method:: _name_changed()
562.. method:: _name_changed(new)
563   :noindex:
564.. method:: _name_changed(old, new)
565   :noindex:
566.. method:: _name_changed(name, old, new)
567   :noindex:
568
569The method name can also be _\ *name*\ _fired(), with the same set of
570signatures.
571
572In these signatures:
573
574* *new* is the new value assigned to the trait attribute.
575* *old* is the old value assigned to the trait attribute.
576* *name* is the name of the trait attribute.  The extended trait name syntax
577  is not supported.
578
579Note that these signatures follow a different pattern for argument
580interpretation from dynamic handlers and decorated static handlers. Both of
581the following methods define a handler for an object's **name** trait::
582
583    def _name_changed( self, arg1, arg2, arg3):
584        pass
585
586    @on_trait_change('name')
587    def some_method( self, arg1, arg2, arg3):
588        pass
589
590However, the interpretation of arguments to these methods differs, as shown in
591the following table.
592
593.. _handler-argument-interpretation-table:
594
595.. rubric:: Handler argument interpretation
596
597======== =================== ================
598Argument _\ *name*\ _changed @on_trait_change
599======== =================== ================
600*arg1*   *name*              *object*
601*arg2*   *old*               *name*
602*arg3*   *new*               *new*
603======== =================== ================
604
605.. _general-static-handler-signatures:
606
607General Static Handler Signatures
608`````````````````````````````````
609
610In the case of a non-attribute specific handler, the method signatures
611supported are:
612
613.. method:: _anytrait_changed()
614.. method:: _anytrait_changed(name)
615   :noindex:
616.. method:: _anytrait_changed(name, new)
617   :noindex:
618.. method:: _anytrait_changed(name, old, new)
619   :noindex:
620
621The meanings for *name*, *new*, and *old* are the same as for
622attribute-specific notification functions.
623
624.. _trait-events:
625
626Trait Events
627------------
628.. index:: events
629
630The Traits package defines a special type of trait called an event. Events are
631instances of (subclasses of) the Event class.
632
633There are two major differences between a normal trait and an event:
634
635* All notification handlers associated with an event are called whenever any
636  value is assigned to the event. A normal trait attribute only calls its
637  associated notification handlers when the previous value of the attribute
638  is different from the new value being assigned to it.
639* An event does not use any storage, and in fact does not store the values
640  assigned to it. Any value assigned to an event is reported as the new value
641  to all associated notification handlers, and then immediately discarded.
642  Because events do not retain a value, the *old* argument to a notification
643  handler associated with an event is always the special Undefined object (see
644  :ref:`undefined-object`). Similarly, attempting to read the value of an event
645  results in a TraitError exception, because an event has no value.
646
647.. index::
648   pair: events; examples
649
650As an example of an event, consider::
651
652    # event.py --- Example of trait event
653    from traits.api import Event, HasTraits, List, Tuple
654
655    point_2d = Tuple(0, 0)
656
657
658    class Line2D(HasTraits):
659        points = List(point_2d)
660        line_color = RGBAColor('black')
661        updated = Event
662
663        def redraw(self):
664            pass  # Not implemented for this example
665
666        def _points_changed(self):
667            self.updated = True
668
669        def _updated_fired(self):
670            self.redraw()
671
672In support of the use of events, the Traits package understands
673attribute-specific notification handlers with names of the form
674_\ *name*\ _fired(), with signatures identical to the _\ *name*\ _changed() functions.
675In fact, the Traits package does not check whether the trait attributes that
676_\ *name*\ _fired() handlers are applied to are actually events. The function
677names are simply synonyms for programmer convenience.
678
679Similarly, a function named on_trait_event() can be used as a synonym for
680on_trait_change() for dynamic notification.
681
682.. index:: Undefined object
683
684.. _undefined-object:
685
686Undefined Object
687````````````````
688
689Python defines a special, singleton object called None. The Traits package
690introduces an additional special, singleton object called Undefined.
691
692The Undefined object is used to indicate that a trait attribute has not yet
693had a value set (i.e., its value is undefined). Undefined is used instead of
694None, because None is often used for other meanings, such as that the value
695is not used. In particular, when a trait attribute is first assigned a value
696and its associated trait notification handlers are called, Undefined is passed
697as the value of the old parameter to each handler, to indicate that the
698attribute previously had no value. Similarly, the value of a trait event is
699always Undefined.
700
701.. _trait-items-handlers:
702
703Container Items Events
704``````````````````````
705.. index::
706    pair: container items; event
707    single: _name_items_changed()
708
709For the container traits (List, Dict and Set) both static and dynamic handlers
710for the trait are only called when the entire value of the trait is replaced
711with another value; they do not get fired when the item itself is mutated
712in-place.  To listen to internal changes, you need to either use a dynamic
713handler with the ``[]`` suffix as noted in the Table
714:ref:`semantics-of-extended-name-notation-table`, or you can define an
715*name*\ _items event handler.
716
717For these trait types, an auxiliary *name*\ _items Event trait is defined which
718you can listen to either with a static handler _\ *name*\ _items_changed()
719or a dynamic handler which matches *name*\ _items, and these handlers will be
720called with notifications of changes to the contents of the list, set or
721dictionary.
722
723.. index:: TraitListEvent, TraitSetEvent, TraitDictEvent
724
725For these handlers the *new* parameter is a :index:`TraitListEvent`,
726:index:`TraitSetEvent` or :index:`TraitDictEvent` object whose attributes
727indicate the nature of the change and, because they are Event handlers, the
728*old* parameter is Undefined.
729
730All of these event objects have **added** and **removed** attributes that
731hold a list, set or dictionary of the items that were added and removed,
732respectively.
733
734The TraitListEvent has an additional **index** attribute that holds either
735the index of the first item changed, or for changes involving slices with
736steps other than 1, **index** holds the _slice_ that was changed.  For
737slice values you can always recover the actual values which were changed or
738removed via ``range(index.start, index.stop, index.end)``.
739
740The TraitDictEvent has an additional **changed** attribute which holds the
741keys that were modified and the _old_ values that those keys held.  The new
742values can be queried from directly from the trait value, if needed.
743
744Handlers for these events should not mutate the attributes of the event
745objects, including avoiding in-place changes to **added**, **removed**, etc.
746
747.. _on-trait-change-dos-n-donts:
748
749
750Dos and Don’ts
751--------------
752
753Don't assume handlers are called in a specific order
754````````````````````````````````````````````````````
755
756Don't do this::
757
758    @on_trait_change("name")
759    def update_number(self):
760        self.number += 1
761
762    @on_trait_change("name")
763    def update_orders(self):
764        if self.number > 5:
765          self.orders.clear()
766
767Do this instead::
768
769    @on_trait_change("name")
770    def update(self):
771        number = self.number + 1
772        self.number = number
773        if number > 5:
774            self.orders.clear()
775
776The first example is problematic because when ``name`` changes, calling
777``update_orders`` after ``update_number``  produces a result that is different
778from calling ``update_number`` after ``update_orders``.
779
780Even if the change handlers appear to be called in a deterministic order,
781this would be due to implementation details that may not hold true across
782releases and platforms.
783
784Don't raise exception from a change handler
785```````````````````````````````````````````
786
787Don't do this::
788
789    name = String()
790
791    @on_trait_change("name")
792    def update_name(self, new):
793        if len(new) == 0:
794            raise ValueError("Name cannot be empty.")
795
796What to do instead depends on the use case. For the above use case, ``String``
797supports length checking::
798
799    name = String(minlen=1)
800
801Traits consider handlers for the same change event to be independent of each
802other. Therefore, any uncaught exception from one change handler will be captured
803and logged, so not to prevent other handlers to be called.
804