def verbose(func): def wrapper(*args, **kwargs): print(f"Arguments were: {args}, {kwargs}") return func(*args, **kwargs) return wrapper @verbose def add(a, b): return a + b print(add(3, 4)) ''' How it works: # The decorator 'verbose' prints the arguments passed to the function 'add' before executing it. # The function 'add' then returns the sum of the two arguments. The decorator is applied using the '@' syntax. ''' def layer1(func): def wrapper(*args, **kwargs): print("layer 1") func(*args, **kwargs) print("layer 1") return wrapper def layer2(func): def wrapper(*args, **kwargs): print("layer 2") func(*args, **kwargs) print("layer 2") return wrapper def layer3(func): def wrapper(*args, **kwargs): print("layer 3") func(*args, **kwargs) print("layer 3") return wrapper @layer1 @layer2 @layer3 def print_hi(message): print(message) print_hi("Hi there!")