Day 24 of 100 - Decorators Day 3 of 3

Decorators Day 3 of 3

Day 24 of 100

Oh, the lightbulbs were really going off for me during this challenge! The majority of my experience with Python has been related to creating web applications with Flask. The code I have written is filled with decorators but I really didn't understand what exactly they did - it was just something I needed to put in specific places to make the code work.

It ended up taking me so much time to get the day 2 challenge done that I didn't complete any of the day three challenges but Bite 22 required me to learn a lot about decorators in order to complete it. First, I had to figure out just how decorators worked and to decorate a function before and after it ran. Then, I had to figure out how to pass input to the function because the challenge was to pass text to a function and then use decorators to wrap that text in html tags using decorators. To figure this out, I had to go down the *args and **kwargs rabbit hole to learn how to pass parameters to functions within decorators. Finally, I also had to figure out how to pass parameters to the decorator because the challenge was to wrap the text with an html tag that took the tag as a parameter of the decorator. Learning all of this made a relatively straightforward Bite quite complicated for a beginner. I got it to work, though and the final code was deceptively simple and I am quite proud of how it turned out.

The challenge was to write a decorator that takes an html tag as a parameter and wraps the text passed to the parent function in the html tag. And you can stack the decorators to wrap the text in multiple tags such that this call:

@make_html('p')
@make_html('strong')
def get_text(text='I call it the "Crunch Enhancer"'):
    return text

Will return the following output:

<p><strong>I call it the "Crunch Enhancer"</strong></p>

It took me a long time to dig in to all of the different things I needed to learn to complete the challenge but I finally got to my solution:

from functools import wraps


def make_html(element):
    def decorator_make_html(func):
        """Wraps text in html tags"""
        @wraps(func)
        def wrapper(*args, **kwargs):
            return f'<{element}>' + func(*args, **kwargs) + f'</{element}>'
        return wrapper
    return decorator_make_html


@make_html('p')
@make_html('strong')
def get_text(text):
    """Text to display on website"""
    return text

I even got it to preserve the docstrings and names using the functools.wraps function. I have to give a lot of credit to Real Python and specifically their Primer on Decorators article for helping me through this challenge!