1# Copyright 2019 Google LLC 2# 3# Licensed under the Apache License, Version 2.0 (the "License"); 4# you may not use this file except in compliance with the License. 5# You may obtain a copy of the License at 6# 7# https://www.apache.org/licenses/LICENSE-2.0 8# 9# Unless required by applicable law or agreed to in writing, software 10# distributed under the License is distributed on an "AS IS" BASIS, 11# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12# See the License for the specific language governing permissions and 13# limitations under the License. 14 15"""Provides a simple memoizing decorator.""" 16 17 18def memoize(f): 19 """Memoizes f. 20 21 The @memoize decorator returns a function which caches the results of f, and 22 returns directly from the cache instead of calling f when it is called again 23 with the same arguments. 24 25 Memoization has some caveats: 26 27 Most importantly, the decorated function will not be called every time the 28 function is called. If the memoized function `f` performs I/O or relies on 29 or changes global state, it may not work correctly when memoized. 30 31 This memoizer only works for functions taking positional arguments. It does 32 not handle keywork arguments. 33 34 This memoizer only works for hashable arguments -- tuples, ints, etc. It does 35 not work on most iterables. 36 37 This memoizer returns a function whose __name__ and argument list may differ 38 from the memoized function under reflection. 39 40 This memoizer never evicts anything from its cache, so its memory usage can 41 grow indefinitely. 42 43 Depending on the workload and speed of `f`, the memoized `f` can be slower 44 than unadorned `f`; it is important to use profiling before and after 45 memoization. 46 47 Usage: 48 @memoize 49 def function(arg, arg2, arg3): 50 ... 51 52 Arguments: 53 f: The function to memoize. 54 55 Returns: 56 A function which acts like f, but faster when called repeatedly with the 57 same arguments. 58 """ 59 cache = {} 60 61 def _memoized(*args): 62 assert all(arg.__hash__ for arg in args), ( 63 "Arguments to memoized function {} must be hashable.".format( 64 f.__name__)) 65 if args not in cache: 66 cache[args] = f(*args) 67 return cache[args] 68 69 return _memoized 70