Skip to content
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

Add memoization to dynamic Callable class #1063

Merged
merged 4 commits into from Jan 16, 2017
Merged
Changes from 1 commit
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.
+17 −1
Diff settings

Always

Just for now

Next

Dynamic Callable memoizes last returned value

  • Loading branch information...
Philipp Rudiger Philipp Rudiger
Philipp Rudiger authored and Philipp Rudiger committed Jan 15, 2017
commit c7716404ec8139a61a9913bde4145594230e118e
Copy path View file
@@ -413,8 +413,22 @@ class Callable(param.Parameterized):
inputs = param.List(default=[], doc="""
The list of inputs the callable function is wrapping.""")

def __init__(self, **params):
super(Callable, self).__init__(**params)
self._memoized = {}

def __call__(self, *args, **kwargs):
return self.callable_function(*args, **kwargs)
inputs = [inp for inp in self.inputs if isinstance(inp, DynamicMap)]

This comment has been minimized.

Copy link
@jlstevens

jlstevens Jan 16, 2017

Contributor

Very minor point - I would call the loop variable i given that inp is a bit weird and you probably don't want to clash with the input built-in. Alternatively, this is one instance of a pure filter so you could consider using that (it would be shorter).

streams = [s for inp in inputs for s in get_nested_streams(inp)]
values = tuple(tuple(sorted(s.contents.items())) for s in streams)

This comment has been minimized.

Copy link
@jlstevens

jlstevens Jan 16, 2017

Contributor

This means it is memoizing on the stream parameters in ascending alphanumeric order. I think that is fine (and makes sense!) but it is worth noting that this is one particular policy for how streams parameters are ordered into a tuple key. This is important to stay consistent if we ever need it somewhere else and I am now wondering if it might be worth having a utility to codify the idea....up to you.

This comment has been minimized.

Copy link
@philippjfr

philippjfr Jan 16, 2017

Author Contributor

It really doesn't matter much, it just needs to be consistently ordered. If we're using it somewhere else it can use the same scheme or another scheme without having any effect here.

This comment has been minimized.

Copy link
@jlstevens

jlstevens Jan 16, 2017

Contributor

True - my point is that we should try to be consistent anyway!

key = args + tuple(sorted(kwargs.items())) + values

if key in self._memoized:
return self._memoized[key]
else:
ret = self.callable_function(*args, **kwargs)
self._memoized = {key : ret}
return ret


def get_nested_streams(dmap):
@@ -500,6 +514,8 @@ class DynamicMap(HoloMap):
""")

def __init__(self, callback, initial_items=None, **params):
if not isinstance(callback, Callable) and not isinstance(callback, types.GeneratorType):
callback = Callable(callable_function=callback)

This comment has been minimized.

Copy link
@jlstevens

jlstevens Jan 16, 2017

Contributor

This means all callbacks will now be wrapped in Callable. This is a change from the previous behavior, and probably a good one (more consistent, at least with __mull__) though we should now document this. It would also be good to have an example of where a user might want to supply Callable themselves....

This comment has been minimized.

Copy link
@jlstevens

jlstevens Jan 16, 2017

Contributor

For instance, we might want an example of the user declaring a Callable with their own set of inputs.

super(DynamicMap, self).__init__(initial_items, callback=callback, **params)

# Set source to self if not already specified
ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.