python foundation - 8 (decorator)

I. nonlocal keyword

def outer():
    num = 0
    def inner():
        # If you want to modify the value of an external function variable (name) in a nested function
        nonlocal num  # Unify the names of L and E (the names in e need to be defined in advance)
        num = 10
        print(num) # 10
    inner()
    print(num)  # 10
outer()
print(num)  # name 'num' is not defined

II. Decorator

Definition:

The essence of function is to add functions to other functions.

Open and closed principle:

1. The source code of the decorated function cannot be modified

2. The calling method of the decorated function cannot be modified

Understand the knowledge reserve of decorators:

1. Function is variable

2. Higher order function

3. Nested function

Higher order function + nested function = = decorator

Higher order function: the variable can point to the function, the parameter of the function can receive the variable, then one function can receive another function as the parameter, which is the higher order function.

#1. Pass a function name as an argument to another function (add function without modifying the source code of the decorated function)

#2. The return value contains the function name (the calling method of the function is not modified)

Examples of higher-order functions:

def add(x,y,f):
    return f(x)+f(y)
res = add(3,-6,abs)
print(res)

Decoration method:

def wrap(fn):
    def inner(*args,**kwargs):
        print("Pre increasing function")
        result = fn(*args,**kwargs)
        print("Post increment function")
        return result
    return inner

@wrap
def fn1():
    print("fn1 Original function of")
@wrap
def fn2(a,b):
    print("fn2 Original function of")
@wrap
def fn3():
    print("fn3 Original function of")
    return True
@wrap
def fn4(a,*,x):
    print("fn4 Original function of")
    return True

fn1()
fn2(10,20)
fn3()
fn4(10,x=20)

Decorator demonstration:

import time
def timmer(func):
    def warpper(*args,**kwargs):
        start_time=time.time()
        func()
        stop_time=time.time()
        print('the func run time is %s'%(stop_time-start_time))
    return warpper()

@timmer   #Grammatical sugar
def test1():
    time.sleep(3)
    print('in the test1')
test1()

Examples of function decorators with parameters and returns:

# Add an account processing function: 3 or more English letters or Chinese characters
def check_usr(fn):
    def inner(usr,pwd):
        if not (len(usr) >= 3 and usr.isalpha()):
            print("Account verification failed")
            return False
        result = fn(usr,pwd)  # login
        return result
    return inner


# Add a password processing function: 6 or more English and numbers
def check_pwd(fn):
    def inner(usr,pwd):
        if not (len(pwd) >= 6 and pwd.isalnum()):
            print("Password verification failed")
            return False
        return fn(usr,pwd)
    return inner


# Login function
@check_usr
@check_pwd
def login(usr,pwd):
    if usr == 'abc' and pwd == '123qwe':
        print("Landing successfully")
        return True
    print("Login failed")
    return False

res = login('abc','123qwe')  # inner
print(res)

#summary
1,login There are parameters, so inner And fn All have the same parameters
2,login There is a return value, so inner And fn All have return values

Decorator with variable length parameter

def wrap(fn):
    def inner(*args,**kwargs):
        result = fn(*args,**kwargs)
        print("New function")
        return result
    return inner

@wrap
def func(a,b,c,*,x,y,z):
    print(a,b,c,x,y,z)
    print("Original function")

func(1,2,3,x=10,y=20,z=30)

Decorator with reference

def outer(input_color):
    def wrap(fn):
        if input_color == 'red':
            info = '\033[31mnew action\033[0m'
        else:
            info = '\033[32mGreen:new action\033[0m'
        def inner(*args,**kwargs):
            result = fn(*args,**kwargs)
            print(info)
            return result
        return inner
    return wrap   # outer(color) --> wrap

color = input("color:")
@outer(color)
def func():
    print('func run')

func()

Login authentication case:

is_login = False  # Landing status

def login():
    usr = input("usr:")
    if not (len(usr) >= 3 and usr.isalpha()):
        print('Account verification failed')
        return False
    pwd = input("pwd:")
    if usr == 'abc' and pwd == '123qwe':
        print('login success')
        is_login = True
    else:
        print('login fail')
        is_login = False

# Finish a decorator of login status verification
def check_login(fn):
    def inner(*args,**kwargs):
        if is_login != True:
            print("You are not logged in.")
            login()
        result = fn(*args,**kwargs)
        return result
    return inner

#View personal home page
@check_login
def home():
    print("Personal homepage")

#Sales function
@check_login
def sale():
    print("Can sell")

home()
sale()

Decorator case advanced:

import time
user,passwd = 'shj','abc123'
def auth(auth_type):
    print("auth func:",auth_type)
    def outer_wrapper(func):
        def wrapper(*args,**kwargs):
            print("wrapper func args:",*args,**kwargs)
            if auth_type == 'local':
                username = input("Username:").strip()
                password = input("Password:").strip()
                if user==username and passwd==password:
                    print("User has passed authentication")
                    res = func(*args,**kwargs)
                    print("-------after authentication")
                    return res
                else:
                    exit("Invalid username or password")
            elif auth_type == 'ldap':
                print("It is so difficult !")
        return wrapper
    return outer_wrapper
def index():
    print("welcome to index page")
@auth(auth_type="local")  #Equivalent to home = wrapper()
def home():
    print("welcome to home page")
@auth(auth_type="ldap")
def bbs():
    print("welcome to bbs page")

index()
home()
bbs()

 

Tags: Programming

Posted on Mon, 02 Dec 2019 10:38:09 -0500 by crazytoon