-
-
Notifications
You must be signed in to change notification settings - Fork 74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Defined pre_set_hooks and post_set_hooks for Parameters #178
Conversation
I should also note that this PR relates to issue #170. |
Seems like a very reasonable extension, but note that it adds two slots to every parameter, and it seems unlikely that this mechanism will be used often, so that seems like a bit of a waste. It would be awkward to do it in a single parameter (e.g. a tuple of the pre,post lists) but wouldn't be that bad; is it worth it? |
Tuples are fine with me. That said, what makes slots expensive to use? Memory consumption? |
Isn't each one given a fixed amount of reserved memory space, per parameter? |
I quickly scanned the diff in hv. I may well be misreading that diff (and I don't know the classes there generally), but it appears to be effectively adding an 'instance-level' update method into the 'class-level' hook list (https://github.com/ioam/holoviews/pull/1740/files#diff-deb386f2061a9a3f41d4982d6a4f7926R203). So, every time you make a new instance, won't a new instance-level update method be added to the class-level hook list, and then when the parameter is set (on the class or on any instance), all those update methods will be called? |
Oh, actually I see it's making a new list each time - but in that case, when the parameter is set on the class or on any instance, it'll be the most recently created instance's update method that'll be called. (Assuming I read it right.) |
Many things seem like they would be reasonable extensions to param. Poor param! ;) I've often vaguely wanted something like this, but never actually needed it in the end. (Or maybe I gave up on doing something cool?) I.e. I want to add this feature, and I don't want to add it! |
Ah, slots. It's been a long time since I was working on any of this, so don't necessarily believe anything I say, but... I'd guess it would be 64 bits per slot per parameter object for most people (one python reference - i.e. one pointer - per slot). And maybe the same again for the list it points to? However, most uses of param don't result in many parameter objects - right? Parameter objects are created by Parameterized classes. Usually the number of instances of classes is much bigger than the number of parameters. (And really we don't expect there to be all that many Parameterized instances, either.) I think the benefit of slots in Parameter comes from e.g. not allowing mistakes in Parameter declarations ( Slots do save memory (vs object with dict), and they do make attribute access faster (vs regular attribute lookup, or because they allow optimized access based on memory address - which could additionally avoid the GIL) but I doubt any of that helps us much. Slots definitely don't save my memory or time whenever I work on param... |
That is right for what I want in HoloViews, though really I only want this hook called when instance parameters are set. This is actually a bit of an annoyance - once you set the hook in the constructor once, it exists at the class level so if you make a new instance, the hook then exists and is called in the constructor of the second object you created, stopping you from setting parameters in the constructor. I think I could easily update this PR to only apply hooks at the instance level, just by checking whether |
Adding slots for this sounds fine in terms of memory; I was thinking they would take space per instance, but if it's per class, I don't think it's worth worrying about. So never mind on the tuple idea; that's just making things harder for ourselves. I'm happy to add this feature as long as we either have found a very clear use case for it by the time of the next release, or we mark it experimental until we have done so. |
I'm +1 on this. It can also eventually be used to replace View parameters I added to paramnb and paramBokeh or at least unify them in some way. |
It would be great to eliminate those, so that objects can be specified using Param only. View parameters work well, but they violate separation of content and presentation, so I'm very much in favor of this PR if indeed it does allow the specification of View parameters to be done at the Param level. |
Do the votes in favor mean positive reviews of how the implementation works now and you want to merge, or of the idea of pre- and post-set hooks in general? Can someone point me to an example using View parameters? |
My +1 was mostly about the idea, I'll look at the implementation now.
There are some examples here: https://github.com/ioam/paramnb/blob/master/doc/AdditionalFeatures.ipynb In essence View parameters declare a post-set hook, which are used to update the display output whenever you set the parameter. |
@@ -609,8 +607,6 @@ def __set__(self,obj,val): | |||
Also applies set_hook, providing support for conversions |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should update this docstring since set_hook
has now been removed.
Okay I see the implementation is very simple. The main question I have is about instance level callbacks. I know you encountered the same issue when you prototyped this so I want to establish what the recommended approach will be. The problem is that you often want to define a callback per instance, e.g. when you create two parameterized instances to use as widgets or two stream instances you don't want setting the parameter on one instance to trigger the set hook installed by another instance. In paramnb/parambokeh I used the object id to trigger only the set hooks for a particular instance, how would you recommend this should be handled now? |
Thanks for the link about View parameters - will check those out.
Unfortunately I still don't understand it :(
Yes, I'm confused about what the desire/intent is here. @jlstevens asked:
I don't think so, no. But I'm not sure about the intent. Can I just double check again that I understand what you are trying to achieve? You want to have something happen to all instances of a class when a parameter is set on any one of them? And can I double check what your implementation does/what you want it do?
If all of the above is right (is it?), I think I'd instead prefer the same kind of semantics as for setting and getting parameter values in general. That is, I'd want to be able to set pre-/post-set hooks per instance or per class, and to know which I'm doing. I would want to be able to say something like these things for class i. Whenever parameter ii. Whenever parameter I don't fully understand your hv example (sorry I still have not tried it out yet!), but if you wanted something to happen to all instances whenever the value of a parameter is set on one instance, you could achieve that by adding one function per instance (e.g. an instance method from each instance) to the class-level hook list.
@philippjfr could you point me to that? Sorry to be lazy and keep asking for pointers but it's tricky for me to keep track of stuff right now.
I would expect the class-level hook list to be overridden and stored at the instance level instead. Unfortunately I still haven't got round to gathering/trying out/understanding the various supplied examples yet to see what it is that actually needs to be supported; I don't want to hold up this PR and be an annoying bottleneck, but I also want to try to protect param a bit. |
No I think this an important discussion since I expect this functionality to be widely used by both holoviews streams and paramnb/parambokeh and we really want to get it right at the param level. Thanks for outlining the various issues so neatly. I agree with everything you've said and setting the hooks at the class/instance level makes sense. Here is what I did in paramnb: view.py#L22 In that version I use a dictionary of |
What Chris outlined makes very good sense to me. Chris, would you be able to implement that, or would you want Philipp (as someone who has already done the same thing one level up, and has a specific use case for it) or Jean-Luc (as the author of this PR, and also has a specific use case) to do it? |
Yes, I'd be happy to continue the implementation once I've understood Jean-Luc's and Philipp's examples (they are likely to have thought of doing things that wouldn't occur to me, and so far I've only looked at the examples superficially). So I'll study the examples mentioned in the comments in more detail (along with another widget example that came up recently in another project) and then implement the above if it seems to fit. |
That was my original goal but as Philipp points out, hooks specific to each instance would also be useful.
That sounds about right. As mentioned earlier, the problem with setting hooks at the class level is you trigger the hooks when trying to set parameters via constructors. There must be a better way than the simple thing I attempted to do here.
Correct. Your parts i and ii outline the per-instance approach (which I didn't attempt).
That is fine, all instance can point to the same function but with the updated suggestion each instance could point to a different function. So in summary, I am in favor of per-instance hooks which isn't currently in this PR. My goal was to do something simple to start a discussion and I think it has now done that job! :-) |
This PR is a prototype that replaces
set_hook
onNumber
with a more general system of pre- and post- setting hooks. This may be useful for things like linking streams or eventual unit support in param.An example of what this might be useful for is shown in holoviz/holoviews#1740.
I'm not quite sure about the appropriate signatures for the hooks right now and this PR will probably need quite a bit of discussion before we are agreed on the appropriate approach.