import os
import time
from functools import wraps
from typing import Any, Callable
def runtime_calculator_without_wraps(func: Callable) -> Callable:
"""Calculate runtime of a function without @wraps"""
def wrapper(*args, **kwargs):
"""wrapper without @wraps"""
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
execution_time = end_time - start_time
print(f"Function `{func.__name__}` executed in {execution_time:.4f} seconds \n")
return result
return wrapper
@runtime_calculator_without_wraps
def print_anything_without_wraps(anything: Any) -> None:
"""Print anything without @wraps
Args:
anything (Any): anything to print
"""
time.sleep(1)
print(anything)
# This returns the `wrapper` function in the decorator, there is no problem with the result
print(print_anything_without_wraps.__name__)
print(print_anything_without_wraps.__doc__)
print_anything_without_wraps("\nHello World")
wrapper wrapper without @wraps Hello World Function `print_anything_without_wraps` executed in 1.0060 seconds
def runtime_calculator_with_wraps(func: Callable) -> Callable:
"""Calculate runtime of a function with @wraps"""
@wraps(func)
def wrapper(*args, **kwargs):
"""wrapper with @wraps"""
start_time = time.time()
result = func(*args, **kwargs)
end_time = time.time()
execution_time = end_time - start_time
print(f"Function `{func.__name__}` executed in {execution_time:.4f} seconds \n")
return result
return wrapper
@runtime_calculator_with_wraps
def print_anything_with_wraps(anything: Any) -> None:
"""Print anything with @wraps
Args:
anything (Any): anything to print
"""
time.sleep(1)
print(anything)
# This returns the original function, the result is the same as the one without @wraps
print(print_anything_with_wraps.__name__)
print(print_anything_with_wraps.__doc__)
print_anything_with_wraps("\nHello World")
print_anything_with_wraps
Print anything with @wraps
Args:
anything (Any): anything to print
Hello World
Function `print_anything_with_wraps` executed in 1.0116 seconds
def set_and_remove_envvar(varname: str, value: str) -> Callable:
"""Set and remove an environment variable"""
def decorator(func: Callable) -> Callable:
@wraps(func)
def wrapper(*args, **kwargs):
"""wrapper"""
os.environ[varname] = value
result = func(*args, **kwargs)
del os.environ[varname]
return result
return wrapper
return decorator
def foobar_without_decorator():
foo = os.getenv("foo")
assert foo is None
print(f"foo is {foo}...")
@set_and_remove_envvar(varname="foo", value="bar")
def foobar_with_decorator():
foo = os.getenv("foo")
assert foo is not None
print(f"foo is {foo}!")
foobar_without_decorator()
foobar_with_decorator()
# After terminating the function, "foo" for the environment variable is removed
print(os.getenv("foo"))
assert os.getenv("foo") is None
foo is None... foo is bar! None