traitlets
traitlets copied to clipboard
Support observe as a decorator outside of classes
Please note that I have only used traitlets as a part of ipywidgets, and not sure how feasible are the suggestions below for its other uses - but for widgets they would be quite useful.
So, when one needs to observe a widget trait, it can't be done without separately defining the handler function and then subscribing:
def handler(*_):
# ... code ...
w.observe(handler, 'value')
Wouldn't it be better if you could just write like this:
@w.observe('value')
def _(*_):
# ... code ...
This way there is also no need to make a name for the handle function.
However, it's often useful to call the handler once after setting everything up, e.g. if you make some plots in the handler it makes sense to display them without forcing user to move a slider or something. So, I also suggest adding an argument to observe, like run=True (looking for a better name :) ) or a separate method observe_and_run which would also execute the handler (in addition to subscribing). This way we still wouldn't have to think of a name for the handler function.
So, instead of:
def handler(*_):
# ... code ...
w.observe(handler, 'value')
handler()
we would be able to write:
@w.observe('value', run=True)
def _(*_):
# ... code ...
So we have considered something like this
@observe('foo.bar')
def _(change):
....
We have to take into account that @observe takes multiple arguments to register the same callback to multiple attributes. The same holds for @validate.
@SylvainCorlay and why observe('foo.bar') instead of foo.observe('bar') which would remain consistent with other parts?
- Because foo.observe and the free observe functions are two different things.
- The former is a method
foo.observe(func, names=['bar', 'baz']) - The latter is to be used as a decorator for methods
@observe('bar', 'baz')
- The former is a method
- Because you may want to observe things from multiple HasTrait instances
@observe('foo.bar', 'fooo.baz')
@SylvainCorlay as for your point 2. - why implement the feature to observe several traits when Python natively allows for this? I mean why not just write (assuming the decorator returns the function passed):
@foo.observe('bar')
@fooo.observe('baz')
def _(*_):
# ... code ...
It also has the benefit of less ambiguity: for example @observe('bar', 'change') looks similar to @observe('bar', type='change') - in the first call 'change' is a name of attribute, and in the second it's the type of event.
@aplavin I don't see @foo.observe being feasible since it would require too many unpleasant heuristics to handle all the ways foo.observe can be called. However, I think this could be done pretty easily:
@observe(*args, owners=(iterable or instance))
def _(change):
# your callback code
By the way, why a HasTrait instance e.g. w supports the w.observe() method to install observers dynamically, but has no respective "public" method for installing dynamic validators?
I said public because I noticed that w._register_validator(...) works quit the same with w.observe().
Am I abusing stuff?
I see two reasons for keeping it private:
- There hasn't been a compelling use case that couldn't be accomplished with the decorator yet. How are you using it?
- We have talked about making coercion different from validation (they are one and the same right now). In which case we might make validators public, but also block them from coercing values. On Fri, May 12, 2017 at 9:51 AM Kostis Anagnostopoulos < [email protected]> wrote:
By the way, why a HasTrait instance e.g. w supports the w.observe() method to install observers dynamically, but has no respective "public" method for installing dynamic validators?
I said public because I noticed that w._register_validator(...) works quit the same with w.observe().
Am I abusing stuff?
— You are receiving this because you commented.
Reply to this email directly, view it on GitHub https://github.com/ipython/traitlets/issues/273#issuecomment-301128809, or mute the thread https://github.com/notifications/unsubscribe-auth/AD2tBqUbZVNYNBYbxXNzYg-L9pZuXhCaks5r5I38gaJpZM4JlQ_z .