MiddleCodeOccasionalNot answered yet
Stacked decorators add_tag('h1') over add_div — implement and order
Implement add_div and the parameterized add_tag(tag) so they wrap a string return value. @add_div makes <div>...</div>; stacking @add_tag('h1') above @add_div yields <h1><div>...</div></h1>.
Requirements:
- Wrap the function's returned string; preserve metadata with
functools.wraps. - Explain why the bottom decorator is applied first.
def add_div(func):
# your code here
Write the implementation.
add_div wraps func's result in <div>...</div>. add_tag(tag) is a factory: it takes the tag, returns a decorator that wraps the result in <tag>...</tag>. Stacked decorators apply bottom-up — @add_div runs first, then @add_tag('h1') wraps that — so the innermost markup is the div and the outer is the h1, giving <h1><div>...</div></h1>. Use @wraps on each wrapper.
- ✗Reversing the application order, getting
<div><h1>...</h1></div> - ✗Writing
add_tagwithout the extra factory layer for its argument - ✗Forgetting
@wraps, losing the decorated function's metadata
- →Why does the decorator nearest the function (bottom) take effect first?
- →How could you define
add_divasadd_tag('div')to avoid duplication?
Contents
Task
Implement add_div and add_tag(tag) that wrap the string result; explain the stacked application order.
Solution
from functools import wraps
def add_div(func):
@wraps(func)
def wrapper(*args, **kwargs):
return f"<div>{func(*args, **kwargs)}</div>"
return wrapper
def add_tag(tag):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
return f"<{tag}>{func(*args, **kwargs)}</{tag}>"
return wrapper
return decorator
@add_tag('h1')
@add_div
def greeting(name):
return f"Hello, {name}!"
# greeting("Mary") -> "<h1><div>Hello, Mary!</div></h1>"
Key points
- The stack applies bottom-up:
add_divfirst, thenadd_tag('h1')on top. add_tagis a factory (three levels) because it takes atagargument.@wrapson each wrapper preservesgreeting's name and docstring.
Contents