@ wraps decorator: let your Python code more short lovely | from simple examples to know it

We used @timer in our last article, adding a small @timer to the function definition so that when the function is finished, it will automatically report its running time to the console.

Like this:

@timer
def piper() :
    for i in range(10000):
        i = i * i ** 10Piper () outputs: timer: using0.00600 s
Copy the code

In fact, the timer logic, @timer, is something we implement ourselves using Python’s decorator feature.

Disassemble the logical

In fact, we can implement the timing logic ourselves without modifiers.

def piper() :
    for i in range(10000):
        i = i * i ** 10

t = time.time()  Record the time when the function starts
piper()
print(f"timer: using {time.time() - t :. 5f} s")  Get the runtime of the function and print it
Copy the code

Notice that when we execute a function, we wrap logic around it. If we want the function to have its own timing logic, we have to define a new function in order to cover the original function.

def time_wrapper(func) :
    # func is a function
    t = time.time()
    func()
    print(f"timer: using {time.time() - t :. 5f} s") time_wrapper(piper) Output: timer: using0.00600 s
Copy the code

When we want to test the running time of a function, we simply type the function name inside time_wrapper.

More elegant improvements

The above code obviously has drawbacks:

  • When we program, the mental burden increases; In addition, the code is more verbose
  • If we just want the function to add a new function, obviouslytime_wrapperNo, because it hasn’t changedpiperitself

So, for today’s wraps, @wraps.

Using our timer as an example, we have all the functions under @timer treated like this:

def timer(func) :
    @wraps(func)
    def inner_func() :
        t = time.time()
        rts = func()
        print(f"timer: using {time.time() - t :. 5f} s")
        return rts
    return inner_func
Copy the code

In piper’s case, we experienced the following changes.

@timer
defThe originalpiper() :
    for i in range(10000):
        i = i * i ** 10
Copy the code

In fact, when you call Piper again, your Internal Piper logic will already be:

defThe currentpiper() :T = time.time() RTS = original piper()print(f"timer: using {time.time() - t :. 5f} s")
    return rts
Copy the code

conclusion

Note that we are actually only modifying functions that have no arguments. There are many more elegant uses for modifiers, such as passing in arguments *args, **kwargs, and the __call__ modifier class. I look forward to meeting good application scenarios in the future and sharing my experience with friends.

Remember to click “watching”!

I am xiao Pai, pay attention to me!