项目作者: jbrt

项目描述 :
The different ways to implement the decorator pattern with Python
高级语言: Python
项目地址: git://github.com/jbrt/python-decorator-patterns.git
创建时间: 2020-08-30T13:27:33Z
项目社区:https://github.com/jbrt/python-decorator-patterns

开源协议:MIT License

下载


Python decorator patterns

There is several way to implement the decorator pattern with Python language.
As far as I Know there is actually four way to do it depending if you want use
classes or functions and if your decorator must take arguments or not.

This repository act here as a memento.
These solutions doesn’t need to use functools.wraps().

Classes decorators

Class decorator without arguments

With a class decorator that doesn’t takes any arguments:

  • reference of the decorated function/object is pass directly to init method
  • arguments for the decorated function/object is pass to call method
  1. class ClassBasedDecorator:
  2. """
  3. A class decorator without arguments
  4. """
  5. def __init__(self, func_to_decorate):
  6. """
  7. Initialization
  8. :param func_to_decorate: function to decorate
  9. """
  10. print("Initialization of the decorator")
  11. self.func_to_decorate = func_to_decorate
  12. def __call__(self, *args, **kwargs):
  13. """
  14. Method that will takes as arguments those from the function to decorate
  15. :param args: (list)
  16. :param kwargs: (dict)
  17. :return: function decorated
  18. """
  19. print("__class__ method of the decorator")
  20. # Something before
  21. response = self.func_to_decorate(*args, **kwargs)
  22. # Something after
  23. return response

Usage of this decorator:

  1. @ClassBasedDecorator
  2. def print_arguments(*args):
  3. for arg in args:
  4. print(arg)

Class decorator with arguments

With a class decorator that takes arguments:

  • arguments passed to decorator are handled by init method
  • reference of the decorated function/object is pass to call method
  • arguments for the decorated function/object is pass to call method
  1. class ClassBasedDecoratorWithParams:
  2. def __init__(self, arg1, arg2):
  3. """
  4. Initialization (takes the arguments of the decorator)
  5. :param arg1: argument one
  6. :param arg2: argument two
  7. """
  8. print("Initialization of the decorator")
  9. print(f'Arguments for decorator: {arg1}, {arg2}')
  10. def __call__(self, fn, *args, **kwargs):
  11. """
  12. This method will take the argument for the decorated function
  13. AND THE FUNCTION TO DECORATE (difference between the previous decorator)
  14. :param fn: function to decorate
  15. :param args: (list)
  16. :param kwargs: (dict)
  17. :return: function decorated
  18. """
  19. print("__call__ method")
  20. def inner_function(*args, **kwargs):
  21. # Something before
  22. print("Function has been decorated. Congratulations.")
  23. response = fn(*args, **kwargs)
  24. # Something after
  25. return response
  26. return inner_function

Usage:

  1. @ClassBasedDecoratorWithParams("arg1", "arg2")
  2. def print_arguments(*args):
  3. for arg in args:
  4. print(arg)

Functions decorators

Functions decorator without arguments

With a function decorator that doesn’t takes any arguments:

  • reference of the decorated function/object is pass directly the decorator function
  • arguments for the decorated function/object is pass to inner function
  1. def decorator_without_argument(func_to_decorate):
  2. """
  3. Function decorator without argument
  4. :param func_to_decorate: function to decorate
  5. :return: function decorated
  6. """
  7. def inner_function(*original_args, **original_kwargs):
  8. print("Enter decorator")
  9. # Something before
  10. response = func_to_decorate(*original_args, **original_kwargs)
  11. # Something after
  12. return response
  13. return inner_function

Usage:

  1. @decorator_without_argument
  2. def print_arguments(*args):
  3. for arg in args:
  4. print(arg)

Functions decorator with arguments

With a function decorator that takes arguments:

  • arguments passed to decorator are handled by decorator function directly
  • reference of the decorated function/object is pass to inner function
  • arguments for the decorated function/object is pass to wrapper function
  1. def decorator_with_argument(arg1, arg2):
  2. """
  3. Function decorator with arguments
  4. :param arg1: (int) first argument
  5. :param arg2: (int) second argument
  6. :return: function decorated
  7. """
  8. def inner_function(func_to_decorate):
  9. def wrapper(*args, **kwargs):
  10. print(f"Enter decorator with arguments: {arg1} & {arg2}")
  11. # Something before
  12. response = func_to_decorate(*args, **kwargs)
  13. # Something after
  14. return response
  15. return wrapper
  16. return inner_function

Usage:

  1. @decorator_with_argument("arg1", "arg2")
  2. def print_arguments(*args):
  3. for arg in args:
  4. print(arg)