Function prints none instead of printing what I want it to print in decorators in Python

Question:

I am studying on decorators in Python. I was trying to use the decorators with arguments. I’m having a problem with the decorators. I defined two inner function in the default decorator function. It returns none when I use it as below:

def prefix(write: bool = False):
    def thread(func):
        def wrapper(*args, **kwargs):
            t1 = Thread(target=func, args=args, kwargs=kwargs)
            t1.start()
            if write:
                print("write parameter is true.")
        return wrapper
    return thread


@prefix(write=True)
def something(x):
    return x + x


print(something(5))

As you see, I defined two different functions named prefix and something. If the write parameter is true, it prints the string. But something function is printing "None" instead of printing 5 + 5.

What’s wrong?

Asked By: Deezwend

||

Answers:

Well, your wrapper() function doesn’t have a return statement, so it will always return None.

Furthermore, how would you expect it to print 5 + 5 (or rather, the result thereof) when that may not have been computed yet, considering you’re starting a new thread to do that and never do anything with the return value of func at all?

IOW, if we expand your example a bit:

import time
from threading import Thread


def prefix(write: bool = False):
    def thread(func):  # <- this function replaces `something`
        def wrapper(*args, **kwargs):
            t1 = Thread(target=func, args=args, kwargs=kwargs)
            t1.start()
            if write:
                print("write parameter is true.")
            return "hernekeitto"

        return wrapper

    return thread


@prefix(write=True)
def something(x):
    print("Computing, computing...")
    time.sleep(0.5)
    print("Hmm, hmm, hmm...")
    time.sleep(0.5)
    print("Okay, got it!")
    return x + x


value = something(9)
print("The value is:", value)

This will print out

Computing, computing...
write parameter is true.
The value is: hernekeitto
Hmm, hmm, hmm...
Okay, got it!

As you can see, the thread’s first print() happens first, then the write print, then the value print, and then the rest of what happens in the thread. And as you can see, we only know what x + x is after "Okay, got it!", so there’s no way you could have returned that out of wrapper() where "hernekeitto" is returned.

See futures (or the equivalent JavaScript concept promises) for a "value that’s not yet ready":

import time
from concurrent.futures import Future
from threading import Thread


def in_future(func):
    def wrapper(*args, **kwargs):
        fut = Future()

        def func_wrapper():
            # Wraps the threaded function to resolve the future.
            try:
                fut.set_result(func(*args, **kwargs))
            except Exception as e:
                fut.set_exception(e)

        t1 = Thread(target=func_wrapper)
        t1.start()
        return fut

    return wrapper


@in_future
def something(x):
    print("Computing, computing...")
    time.sleep(0.5)
    print("Hmm, hmm, hmm...")
    time.sleep(0.5)
    print("Okay, got it!")
    return x + x


value_fut = something(9)
print("The value is:", value_fut)
print("Waiting for it to be done...")
print("Here it is!", value_fut.result())

This prints out

Computing, computing...
The value is: <Future at 0x... state=pending>
Waiting for it to be done...
Hmm, hmm, hmm...
Okay, got it!
Here it is! 18

so you can see the future is just a "box" where you’ll need to wait for the actual value to be done (or an error to occur getting it).

Normally you’d use futures with the executors in concurrent, but the above is an example of how to do it by hand.

Answered By: AKX
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.