def trace(func): """A decorator that accepts the same arguments and returns the same value as FUNC, but also prints the arguments and return value.""" def afunc(*args): print("Call", func.__name__, "with", args) v = func(*args) print(func.__name__, "returns", v) return v return afunc @trace def sum_squares(k): if k <= 0: return 0 else: return k*k + sum_squares(k-1) sum_squares(3) def check_result(checker): """A decorator that applies the predicate CHECKER to the result of the decorated function and raises an error if the check fails.""" def checked_func(func): def call_and_check(*args): result = func(*args) if checker(result): return result else: raise ValueError("bad result") # indicate an error return call_and_check return checked_func @check_result(lambda x: x < 1000) def limited_id(y): return y print(limited_id(5)) print(limited_id(1000)) # Raises exception