A decorator

This article is participating in Python Theme Month,See the event link for details

Decorators are an important part of Python. In short: they are functions that modify the functionality of other functions. Most beginners don’t know where to use them, so I’ll share some decorators to make your code cleaner.

First, let’s discuss how to write your own decorators.

This is probably one of the most difficult concepts to grasp. We’ll take it step by step so you can fully understand it.

1. Everything in Python is an object:

First, let’s look at functions in Python:

def test(name="dm") :
    return "Hello" + name

print(test())
>>> 'hello dm'
Copy the code

2. Define a function in a function:

So these are the foundations of functionality. Let us know more about you. In Python, we can define functions within other functions:

def test(name="dm") :
    print("I am 111")

    def inside1() :
        return "inside11"

    def inside2() :
        return "inside22"

    print(inside1())
    print(inside2())

test()
>>> I am a111
    inside11
    inside22


inside1()  # Can't call a function directly from the outside
>>> NameError: name 'inside1' is not defined
Copy the code

So now we know that we can define functions in other functions. In other words: we can create nested functions. Now one thing you need to learn is that functions can also return functions.

Return a function from inside a function:

There is no need to execute a function in another function, we can also return it as output:

def test(name="dm") :
    def inside1() :
        return "inside11"

    def inside2() :
        return "inside22"

    if name == "dm":
        return inside1
    else:
        return inside2

a = hi()
print(a)
>>> <function inside1 at 0x7f21e36594>


print(a())
>>> inside11
Copy the code

In the if/else clause, we return inside1 and inside2 instead of inside1() and inside2(). Why is that? This is because when you put parentheses after it, the function is executed; If you don’t put parentheses after it, then it can be passed and assigned to another variable without executing it.

4. Take one function as an argument to another:

def test():
    return "hi boy!"

def inner(func):
    print("inner1")
    print(func())

inner(test)
>>> inner1
    hi boy!
Copy the code

You now have all the necessary knowledge to understand what a decorator is. Decorators let you execute code before and after a function.

5. Write your first decorator:

In the last example, we actually made a decorator! Let’s modify the previous decorator and make a more useful program:

def outside(func) :

    def inner() :
        print("inner1")
        func()
    return inner

def abc() :
    print("hihihihi")

abc()
>>> "hihihihi"

a = outside(abc)

a()
>>> inner1
    hihihihi

Copy the code

We’re just applying the principles we learned earlier. This is exactly what decorators do in Python! They wrap a function and modify its behavior one way or another. Now you might be wondering why we didn’t use @ anywhere in the code? This is just a short way to compose a decorative function. Here’s how we ran the previous code example using @.

@outside
def abc():
    print("hihihihi")

a = outside(abc)

a()
>>> inner1
    hihihihi
Copy the code

It’s much better now. Let’s move on to some decorator use cases.

The sample

from functools import wraps
def decorator_name(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        if not can_run:
            return "Function will not run"
        return f(*args, **kwargs)
    return decorated

@decorator_name
def func():
    return("Function is running")

can_run = True
print(func())
>>> Output: Function is running

can_run = False
print(func())
>>> Output: Function will not run
Copy the code

Note: @wraps takes the function to decorate and adds the ability to copy the function name, docstrings, argument lists, and so on. This allows us to access the properties of the predecorated function in the decorator.

5.1. Use cases:

Now let’s look at where decorators really come into play, and their use makes something very manageable.

Authorized by 5.2.

Decorators can help check whether someone is authorized to use an endpoint in a Web application. They are widely used in the Flask Web framework and Django. Here’s an example of using decorator-based authentication:

Example:

from functools import wraps

def requires_auth(f):
    @wraps(f)
    def decorated(*args, **kwargs):
        auth = request.authorization
        if not auth or not check_auth(auth.username, auth.password):
            authenticate()
        return f(*args, **kwargs)
    return decorated
Copy the code

5.3. Log recording

Logging is another area where decorators shine. Here’s an example:

from functools import wraps

def logit(func):
    @wraps(func)
    def with_logging(*args, **kwargs):
        print(func.__name__ + " was called")
        return func(*args, **kwargs)
    return with_logging

@logit
def addition_func(x):
   """Do some math."""
   return x + x


result = addition_func(4)
# Output: addition_func was called
Copy the code

I’m sure you’re already thinking about some clever uses for decorators.

Decorator conditions:

1. The inner function is defined in the outer function. 2. The outer function must have a return value. The inner function refers to the variable of the outer functionCopy the code

Using decorators:

@ decorator name def function name (): passCopy the code
  1. Simple decorators

    Refer to a function as an argument to an outer function in the context of a closure

    Import time # decorator with argument def zhuang1(func): # receive f1 function as argument def wrapper(*args, **kwargs): # add *args,**kwargs 1 here. The outer function defines the inner function print(" checking.....") ) time.sleep(2) print(" check completed.....") Func (*args, **kwargs) # Function as the outer function argument return wrapper # returns the decorator to F1 2. @zhuang1 def f1(): print(" I'm one------one") f1()Copy the code
  2. A function that takes arguments

    Import time # with def zhuang1(func): # receive F1 def wrapper(*args, **kwargs): # add *args,**kwargs print(" checking.....") ) time.sleep(2) print(" check completed.....") Sum = 10000@zhuang1 def f1(sum): Print (" I am one------one", sum) f1(sum) @zhuang1 def f2(sum, name=" ABC "): Format (name), sum) f2(sum) @zhuang1 def f2(sum, name="aaaaaa"): Print (" I am the owner {}-----two". Format (name), sum) f2(sum, name="adfafasdasd"Copy the code
  3. Decorated functions have return values

    Make sure you return the original function

    Def say(func): def inner(): Print (" -- -- -- -- -- -- -- -- -- -- 2 ") return func () # here must return to the function return inner @ say def show () : the return "-- -- -- -- -- 1 -- -- -- -- --" print (show ())Copy the code
  4. Use multiple decorators to decorate the same function

    "" def zhuangfeng1(func):" "def warper(): print("-----one-- start") Print ("end") return warper def zhuangfeng2(func): # define a decorator 2 print (" -- -- -- -- -- two - start ") def warper () : print (" scutching pepper.." @zhuangfeng2 @zhuangfeng1 def fz1(): Return "the head of the household" print (fz1 ()) "" "-- -- -- -- -- one -- -- -- -- -- -- - start end two - start end scutching pepper.. Brush paint.. When multiple decorators are applied to the same function, they are executed from top to bottom, but the original function is only called onceCopy the code
  5. Decorators take arguments

    There are three layers

    Def outer(a); def outer(a); def outer(a); def outer(a); Def wraper(*args, **kwargs): / / def wraper(*args, **kwargs) # Third layer: Buy an argument to the receive function func(*args, **kwargs) print(" classpath ".format(a)) return wraper return classpath @outer(100) # def house(time): Print (" I {} date got the blank room ".format(time)) house("2020-9-9")Copy the code