code: def _memoize(f):
    
    nothing = object()  # Unique "no value" sentinel object.
    cache = {}
    # Use a reentrant lock so that if f references the resulting wrapper we die
    # with recursion depth exceeded instead of deadlocking.
    lock = threading.RLock()
    @functools.wraps(f)
    def wrapper(arg):
      if cache.get(arg, nothing) is nothing:
        with lock:
          if cache.get(arg, nothing) is nothing:
            cache[arg] = f(arg)
      return cache[arg]
    return wrapper
docs: Memoizing decorator for f, which must have exactly 1 hashable argument.