<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def rate_limited(self, key_function=None):
 """ Function or method decorator that will prevent calls to the decorated function when the number of events has been exceeded for the given time period. It is probably important that you take care to choose an appropiate key function. For instance, if rate-limiting a web-page you might use the requesting user's IP as the key. If the number of allowed events has been exceedd, a ``RateLimitException`` will be raised. :param key_function: Function that accepts the params of the decorated function and returns a string key. If not provided, a hash of the args and kwargs will be used. :returns: If the call is not rate-limited, then the return value will be that of the decorated function. :raises: ``RateLimitException``. """

        if key_function is None:
            def key_function(*args, **kwargs):
                data = pickle.dumps((args, sorted(kwargs.items())))
                return hashlib.md5(data).hexdigest()

        def decorator(fn):
            @wraps(fn)
            def inner(*args, **kwargs):
                key = key_function(*args, **kwargs)
                if self.limit(key):
                    raise RateLimitException(
                        'Call to %s exceeded %s events in %s seconds.' % (
                            fn.__name__, self._limit, self._per))
                return fn(*args, **kwargs)
            return inner
        return decorator