A decorator to print the output

To explain what is a decorator, let’s make the simpliest one. We make a function that calculates how many seconds have passed giving a time like 10:18 (could be used, for example to get the time into a youtube video to make it start from that time). You can add a print into the function simply, but you could also use a decorator, another function that takes the original function and makes something with it, like printing the output, to make a very basic thing. To make it go through the decorator you got to add @dec becore the declaration of the function, where dec is the name of the decorator function.

notebook decorator

def dec(f):
    ''' printing the output of the function '''
    def wrapper(t):
        print(f(t))
    return wrapper


@dec 
def convert(timestr)-> int:
    ''' return the seconds of a 10:30 like time '''
    h,m = timestr.split(":")
    n = int(h)*60 + int(m)
    return n

xtm = convert("10:18")

How to choose if you want the decorator or not

I thought to this solution in case you wanna choose if you want decorator or not without having to change the code (sort of):

def dec(f):
    def wrapper(t, dec=1):
        if dec:
            print(f"Decorator on: \n\tseconds = {f(t)}")
        else:
            print("Decorator off - output will not be shown")
    return wrapper


@dec 
def convert(timestr, dec=1):
    h,m = timestr.split(":")
    n = int(h)*60 + int(m)
    return n

xtm = convert("10:18")

Decorator on

So the output if you do not specify the second argument will be by default:

Decorator off

If you, instead make the second parameters equal to zero… the output will not be shown, like there is no decorator. Actually I made some print statement to make it more obvious, but you could just put pass in the else stament or do not put it at all if you want that the decorator is not effective at all when you put the dec parameter equal to zero.

This is how I figured it out. Do you think it’s a good way to make it? Leave a comment down below if you like to have this discussion with me.

Let’s redesign the code a little bit:

def dec(f):
    ''' decorator '''
    def wrapper(t, dec=1):
        if dec:
            print("Decorator on (dec=1)") 
            print(f"Time: {t} = {f(t)[1]} seconds")
        else:
            print("Decorator off (dec=0)")
    return wrapper


@dec 
def convert(timestr, dec=1):
    ''' this will be decorated if dec=1 '''
    h,m = timestr.split(":")
    n = int(h)*60 + int(m)
    return timestr, n

# Put dec=0 if to "hide" the decorator
xtm = convert("10:18",1)

Understanding what actually is going on

Ok, if you, like me do not really get what the heck is goin’ on with the decorator, let’s try to decode what is happening with some print statement

def dec(f):
    ''' decorator '''
    print("1. Into decorator function")
    def wrapper(t, dec=1):
        print("3. Now I am in the wrapper of dec")
        if dec:
            print("4. Decorator on (dec=1)") 
            print(f"6. Time: {t} = {f(t)[1]} seconds")
        else:
            print("Decorator off (dec=0)")
    return wrapper

print("0. Now I am here before @dec")
@dec
def convert(timestr, dec=1):
    ''' this will be decorated if dec=1 '''
    print("5. Into convert")
    h,m = timestr.split(":")
    n = int(h)*60 + int(m)
    return timestr, n

# Put dec=0 if to "hide" the decorator
print("2. Now I am outside of the functions")
xtm = convert("10:18",1)

The output is this

Ok, so

  1. First the @dec calls the function dec until the inner wrapper function.
  2. then it continues going to xtm = convert(“10:18, 1) that calls convert function
  3. now it goes into the inner wrapper function and execute it
  4. when in the wrapper it is called the function in line 8, it first prints what is in the convert print statement and then it prints the print statement in the wrapper function, it is a good thing, since it needs to calculate the output of the function before printing it after “Time: ….”.

Ok, now I feel I have a better understanding of what goes on in the decorator function, I am quite satisfied.

Let’s make it even more verbose

def dec(f):
    ''' decorator '''
    print("1. Into decorator because of @dec")
    print("------- (but still not in the wrapper)")
    def wrapper(t, dec=1):
        print("3. I called convert, but the code run in the wrapper first")
        if dec:
            print("4. Now the output of convert here") 
            print(f"6. After calculating output in convert-> Time: {t} = {f(t)[1]} seconds")
        else:
            print("Decorator off (dec=0)")
    return wrapper

print("0. Now I am here before @dec")
@dec
def convert(timestr, dec=1):
    ''' this will be decorated if dec=1 '''
    print("5. Into convert")
    h,m = timestr.split(":")
    n = int(h)*60 + int(m)
    return timestr, n

# Put dec=0 if to "hide" the decorator
print("2. Now I am going to call the convert function")
xtm = convert("10:18",1)
print("7. Now it is really over")

Subscribe to the newsletter for updates
Tkinter templates
Avatar My youtube channel

Twitter: @pythonprogrammi - python_pygame

Videos

Speech recognition game

Pygame's Platform Game

Other Pygame's posts

Published by pythonprogramming

Started with basic on the spectrum, loved javascript in the 90ies and python in the 2000, now I am back with python, still making some javascript stuff when needed.