docs: def memoize(f):
      '''
      Caches result of a function
      From: https://goo.gl/aXt4Qy
  
      >>> import time
      
      >>> @memoize
      ... def test(msg):
      ...     # Processing for result that takes time
      ...     time.sleep(1)
      ...     return msg
      >>>
      >>> for i in range(5):
      ...     start = time.time()
      ...     test('calling memoized function')
      ...     time_taken = time.time() - start
      ...     # For first time it takes usual time
      ...     if i == 0 and time_taken >= 1: print('ok')
      ...     # Faster from the 2nd time
      ...     elif i != 0 and time_taken <= 1: print('ok')
      ...     else: print('NOT ok!')
      'calling memoized function'
      ok
      'calling memoized function'
      ok
      'calling memoized function'
      ok
      'calling memoized function'
      ok
      'calling memoized function'
      ok
      '''
      class memodict(dict):
  
          @wraps(f)
          def __getitem__(self, *args):
              return super(memodict, self).__getitem__(*args)
  
          def __missing__(self, key):
              self[key] = ret = f(key)
              return ret
      return memodict().__getitem__