简体   繁体   中英

Decorator vs Function without wrapper - Python

I am currently trying to understand what decorators are and what they are used for. Until now, I've learned that they are just functions which pass and return functions as arguments and their purpose is to modify a function w/o modifying the original function.

My question is related to the classic structure used to define them. Usually you define a decorator function and within it, another function called wrapper which is returned by the decorator function.

So my question is, why is wrapper created inside the decorator when it could be done with just a function? Would`t it be more "pythonic" to reduce code side by doing so?

As an example, the following 2 pieces of code:

def country(func):
    def wrapper_function():
        print("The name of my favorite country is: ")
        return func()
    return wrapper_function

@country # == fav_country = country(fav)
def fav():
    print("Sweden")

fav()

OUTPUT:

The name of my favorite country is:

Sweden

def country(func):
    print("The name of my favorite country is: ")
    return func

@country # == fav_country = country(fav)
def fav():
    print("Sweden")

fav()

OUTPUT: The name of my favorite country is:

Sweden

You are correct that a decorator is nothing else then a function taking a function as an argument and returning a function. But these two:

def country1(func):
    def wrapper_function():
        print("The name of my favorite country is: ")
        return func()
    return wrapper_function

def country2(func):
    print("The name of my favorite country is: ")
    return func

are not equivalent. Consider

@country1
def fav1():
    print("Sweden")

@country2
def fav2():
    print("Sweden")

and see what happens when you call

fav1()
fav1()
fav1()

and

fav2()
fav2()
fav2()

Your country2 doesn't modify the original function and the result is The name of my favorite country is: printed only once during decoration process (at function declaration). While country1 changes the behaviour of the decorated function, you will see the message three times.

In your case a wrapper function isn't needed. You aren't doing anything with the passed parameters and the return parameters.

def printall(func):
    def inner(*args):
        print('Arguments for args: {}'.format(args))
        return func(*args)
    return inner

@printall
def random_func(*args):
    return sum(*args)

a = random_func(2, 2)

It is useful if for instance you want the passed parameters to start with a higher value (sort of like an added offset). Then you could do:

def offset(func):
    def inner(*args):
        args = [arg + 2 for arg in args]
        return func(*args) # <-- here it is calling your random_func with modified passed parameters!
    return inner

@offset
def random_func(*args):
    return sum(*args)

a = random_func(2, 2)

So when modifying the passed parameters you have to use a wrapper to achieve this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM