blob: fbd46c44f43700f9a80a90c7b2d6fb618d9836a8 [file] [log] [blame]
# Copyright 2019 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Provides a simple memoizing decorator."""
def memoize(f):
"""Memoizes f.
The @memoize decorator returns a function which caches the results of f, and
returns directly from the cache instead of calling f when it is called again
with the same arguments.
Memoization has some caveats:
Most importantly, the decorated function will not be called every time the
function is called. If the memoized function `f` performs I/O or relies on
or changes global state, it may not work correctly when memoized.
This memoizer only works for functions taking positional arguments. It does
not handle keywork arguments.
This memoizer only works for hashable arguments -- tuples, ints, etc. It does
not work on most iterables.
This memoizer returns a function whose __name__ and argument list may differ
from the memoized function under reflection.
This memoizer never evicts anything from its cache, so its memory usage can
grow indefinitely.
Depending on the workload and speed of `f`, the memoized `f` can be slower
than unadorned `f`; it is important to use profiling before and after
memoization.
Usage:
@memoize
def function(arg, arg2, arg3):
...
Arguments:
f: The function to memoize.
Returns:
A function which acts like f, but faster when called repeatedly with the
same arguments.
"""
cache = {}
def _memoized(*args):
assert all(
arg.__hash__ for arg in args
), "Arguments to memoized function {} must be hashable.".format(f.__name__)
if args not in cache:
cache[args] = f(*args)
return cache[args]
return _memoized