Explain the purpose and benefits of using decorators in Python. Provide examples of different types of decorators you have implemented or used.
Decorators in Python are a powerful way to modify or extend the behavior of functions or methods. They are commonly used for tasks such as logging, timing, and caching. Here's an example:
def my_decorator(func):
def wrapper():
print("Something is happening before the function is called.")
func()
print("Something is happening after the function is called.")
return wrapper
@my_decorator
def say_hello():
print("Hello!")
say_hello()