Decorators Basics

Basic Decorator

  1. # simple decorator
  2. def my_decorator(func):
  3. def wrapper():
  4. print("Before")
  5. func()
  6. print("After")
  7. return wrapper
  8. @my_decorator
  9. def say_hello():
  10. print("Hello!")
  11. say_hello()
  12. #ans: Before
  13. #ans: Hello!
  14. #ans: After

Decorator with Arguments

  1. # decorator for functions with args
  2. def my_decorator(func):
  3. def wrapper(*args, **kwargs):
  4. print("Before")
  5. result = func(*args, **kwargs)
  6. print("After")
  7. return result
  8. return wrapper
  9. @my_decorator
  10. def add(a, b):
  11. return a + b
  12. add(5, 3)
  13. #ans: Before, After, returns 8

Manual Decoration

  1. # without @ syntax
  2. def greet():
  3. print("Hello")
  4. greet = my_decorator(greet)
  5. #ans: equivalent to @my_decorator

Preserving Metadata

  1. from functools import wraps
  2. # preserve function info
  3. def my_decorator(func):
  4. @wraps(func)
  5. def wrapper(*args, **kwargs):
  6. return func(*args, **kwargs)
  7. return wrapper
  8. @my_decorator
  9. def my_func():
  10. """Docstring"""
  11. pass
  12. my_func.__name__
  13. #ans: "my_func" (not "wrapper")

Exercises - Part 1

  1. # what is returned?
  2. def decorator(func):
  3. def wrapper():
  4. return func()
  5. return wrapper
  6. @decorator
  7. def func():
  8. return 5
  9. func()
  10. #ans: 5

Exercises - Part 2

  1. # decorator execution?
  2. def decorator(func):
  3. print("Decorating")
  4. return func
  5. @decorator
  6. def func():
  7. pass
  8. #ans: "Decorating" (at definition time)

Exercises - Part 3

  1. # nested decorators?
  2. def dec1(func):
  3. def wrapper():
  4. print("1")
  5. return func()
  6. return wrapper
  7. def dec2(func):
  8. def wrapper():
  9. print("2")
  10. return func()
  11. return wrapper
  12. @dec1
  13. @dec2
  14. def func():
  15. pass
  16. func()
  17. #ans: 1, 2 (bottom to top)

Exercises - Part 4

  1. # decorator without wrapper?
  2. def decorator(func):
  3. return func
  4. @decorator
  5. def func():
  6. pass
  7. #ans: valid (identity decorator)

Exercises - Part 5

  1. # accessing original?
  2. def decorator(func):
  3. def wrapper():
  4. return func()
  5. wrapper.original = func
  6. return wrapper
  7. @decorator
  8. def func():
  9. pass
  10. func.original

Exercises - Part 6

  1. # decorator modifying return?
  2. def double(func):
  3. def wrapper(*args):
  4. return func(*args) * 2
  5. return wrapper
  6. @double
  7. def add(a, b):
  8. return a + b
  9. add(2, 3)
  10. #ans: 10

Exercises - Part 7

  1. # decorator with closure?
  2. def make_bold(func):
  3. def wrapper():
  4. return f"<b>{func()}</b>"
  5. return wrapper
  6. @make_bold
  7. def get_text():
  8. return "Hello"
  9. get_text()
  10. #ans: "<b>Hello</b>"

Exercises - Part 8

  1. # class as decorator?
  2. class Decorator:
  3. def __init__(self, func):
  4. self.func = func
  5. def __call__(self, *args):
  6. return self.func(*args)
  7. @Decorator
  8. def func():
  9. pass

Exercises - Part 9

  1. # without @wraps?
  2. def decorator(func):
  3. def wrapper():
  4. return func()
  5. return wrapper
  6. @decorator
  7. def func():
  8. pass
  9. func.__name__
  10. #ans: "wrapper"

Exercises - Part 10

  1. # decorator return None?
  2. def decorator(func):
  3. def wrapper():
  4. func()
  5. return wrapper
  6. @decorator
  7. def func():
  8. return 5
  9. func()
  10. #ans: None (wrapper doesn't return)

Google tag (gtag.js)