def METHOD_NAME(func: Callable):
    """The actual decorator that accept function as input."""
    class HashableNpArray(np.ndarray):
        def __new__(cls, input_array):
            # Input array is an instance of ndarray.
            # The view makes the input array and returned array share the same data.
            obj = np.asarray(input_array).view(cls)
            return obj
        def __eq__(self, other) -> bool:
            return np.array_equal(self, other)
        def __hash__(self):
            # Hash the bytes representing the data of the array.
            return hash(self.tobytes())
    @functools.lru_cache(maxsize=max_size, typed=typed)
    def cached_func(*args, **kwargs):
        """This function only accepts `HashableNpArray` as input params."""
        return func(*args, **kwargs)
    # Preserves original function.__name__ and __doc__.
    @functools.wraps(func)
    def decorated_func(*args, **kwargs):
        """The decorated function that delegates the original function."""
        def convert_item(item: Any):
            return HashableNpArray(item) if isinstance(item, np.ndarray) else item
        args = [convert_item(arg) for arg in args]
        kwargs = {k: convert_item(arg) for k, arg in kwargs.items()}
        return cached_func(*args, **kwargs)
    return decorated_func