装饰器:


定义

  装饰器 本质是函数; 器代表函数;

功能

  装饰其他函数,就是为其他函数添加附加功能;

原则

  1.不能修改被装饰的函数的源代码

  2.不能修改被装饰的函数的调用方式

  装饰器对被装饰的函数是透明的。感受不到装饰器的存在。

实现装饰器知识储备:


1.函数即“变量”


一个简单的装饰器例子

import time
定义装饰器
def timmer(func):
    def warrper(*args,**kwargs):
        start_time=time.time()
        func()
        stop_time=time.time()
        print("the func run time is %s"%(stop_time-start_time))
    return warrper
@timmer
def test1():
    time.sleep(3)
    print("in the test1")
test1()


举例说明:

def foo():
    print("in the foo")
    bar()
foo()
报错bar没有定义
def bar():
    print("in the bar")
def foo():
    print("in the foo")
    bar()
foo()
正常运行
def foo():
    print("in the foo")
    bar()
def bar():
    print("in the bar")
foo()
正常运行

运行该例子的时候,先将定义的函数foo、bar依次存储到了内存;

然后在运行foo(),调用bar是在内存中存在的,所以不会报错。

def foo():
    print("in the foo")
    bar()
foo()
def bar():
    print("in the bar")
foo()
会报错提示bar没有定义

执行foo(),先将foo函数存储到内存,然后就运行foo;

而此时bar函数还没有定义写到内存中,找不到bar所以会报错。


总结:

    定义一个函数就相当于将函数体赋值给函数名;

    定义变量/函数 是先定义,再执行;

    函数和变量一样都会被python内存回收机制回收;

    所以:函数即“变量”

1.1匿名函数

#函数没有名字,下面给函数定义了一个变量名来引用;

niming = lambda x:x*3
print (niming(3))

2.高阶函数

a:把一个函数名当做实参给另外一个函数;

(在不修改被装饰函数源代码的情况下为其添加功能)

b:返回值中包含函数名;

(不修改函数的调用方式)

把函数当作一个实参传递给形参。


简单例子

def bar():
    print("in the bar")
def test1(func):
    print(func)
    func()
test1(bar)
func()等于下面
func=bar
func()


稍作改变

def bar():
    time.sleep(0.3)
    print("in the bar")
def test1(func):
    start_time=time.time()
    func()
    stop_time=time.time()
    print("the func run time is %s" %(stop_time-start_time))
test1(bar)

总结:(在不修改被装饰函数源代码的情况下为其添加功能)


def bar():
    time.sleep(0.3)
    print("in the bar")
def test2(func):
    print(func)
    return func
运行1
print(test2(bar))
运行2
t = test2(bar)
t()
#运行3
bar=test2(bar)
bar()
bar是原函数


总结:返回值中包含函数名; (不修改函数的调用方式)



写一个装饰器(高阶函数)

import  time
def deco(func):
    star_time= time.time()
    func()
    stop_time=time.time()
    print("th func run time is %s"%(stop_time-star_time))
def deco(func):
    star_time= time.time()
    return func
    stop_time=time.time()
    print("th func run time is %s"%(stop_time-star_time))
def test1():
    time.sleep(3)
    print("in the test1")
def test2():
    time.sleep(3)
    print("in the test2")
deco(test1)
deco(test2)
test1=deco(test1)
test1()
test2=deco(test2)
test2()
结束时间没有运行;


3.嵌套函数

高阶函数+嵌套函数= 装饰器


变化1

def timmer(func):
    def deco():
        star_time= time.time()
        func()
        stop_time=time.time()
        print("th func run time is %s"%(stop_time-star_time))
    return deco
def test1():
    time.sleep(3)
    print("in the test1")
def test2():
    time.sleep(3)
    print("in the test2")
test1=timmer(test1)
test1()
test2=timmer(test2)
test2()


变化2 应用装饰器 嵌套函数

def timmer(func):
    def deco():
        star_time= time.time()
        func()
        stop_time=time.time()
        print("th func run time is %s"%(stop_time-star_time))
    return deco
@timmer     #@timmer 就等于test1=timmer(test1)  ;这就是装饰器
def test1():
    time.sleep(3)
    print("in the test1")
@timmer
def test2():
    time.sleep(3)
    print("in the test2")
test1()
test2()



变化3 高级装饰器  可以满足日常90%的需求

def timmer(func):
    def deco(*args,**kwargs):
        star_time= time.time()
        func(*args,**kwargs)
        stop_time=time.time()
        print("th func run time is %s"%(stop_time-star_time))
    return deco
@timmer     #@timmer 就等于test1=timmer(test1)  ;这就是装饰器
def test1():
    time.sleep(3)
    print("in the test1")
@timmer
def test2(name,age):
    time.sleep(3)
    print("in the test2:name age")
test1()
test2("abc",123)



终极高级版 decorator 就是装饰器的意思;


一、默认谁都可以访问三个网站

def index():
    print("welcome to index page")
def home():
    print("welcome to home page")
def bbs():
    print("welcome to bbs page")
index()
home()
bbs()


二、一部分home/bbs需要登录才能浏览

user,passwd="abc","123"
def auth(func):
    def wrapper(*args,**kwargs):
        username = input("Username:").strip()
        password = input("Password:").strip()
        if user == username and passwd == password:
            print("\033[32;1m Auth is sucessed!\033[0m")
            func(*args,**kwargs)
        else:
            print("\033[31;1m Auth is failed!\033[0m")
    return wrapper
def index():
    print("welcome to index page")
@auth
def home():
    print("welcome to home page")
@auth
def bbs():
    print("welcome to bbs page")
index()
home()
bbs()


三、一部分home/bbs需要登录才能浏览

user,passwd="abc","123"
def auth(func):
    def wrapper(*args,**kwargs):
        username = input("Username:").strip()
        password = input("Password:").strip()
        if user == username and passwd == password:
            print("\033[32;1m Auth is sucessed!\033[0m")
            ret = func(*args,**kwargs)  #from home  ; 也可以直接return
            print("-----after auth ")
            return ret
        else:
            print("\033[31;1m Auth is failed!\033[0m")
    return wrapper  #而这里没有返回值;在上边return ret之后就有数据了
def index():
    print("welcome to index page")
@auth
#当home有return结果的时候,用上边的无法获取到home return的结果;wrapper加一个return;
def home():
    print("welcome to home page")
    return "From home!"
@auth
def bbs():
    print("welcome to bbs page")
index()
print(home())     #调用home相当于调用wrapper
bbs()





四、home bbs两个目录,一部分可以直接访问,一部分需要登录才能浏览

以上案例是验证写死的,运维中有本地认证和ldap认证,认证方式有多种,需要以下完成;

home用本地认证,bbs用远程ldap认证;

import time
user,passwd="abc","123"
def auth(auth_type):
    print(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("\033[32;1m Auth is sucessed!\033[0m")
                    ret = func(*args, **kwargs)  # from home,就是去运行home ; 也可以直接return
                    print("-----after auth ")
                    return ret
                else:
                    print("\033[31;1m Auth is failed!\033[0m")
            elif auth_type == "ldap":
                print("no no no ldap!")
        return wrapper  # 而这里没有返回值;在上边return ret之后就有数据了
    return outer_wrapper
def index():
    print("welcome to index page")
#当home有return结果的时候,用上边的无法获取到home return的结果;wrapper加一个return;
@auth(auth_type="local")   #home = auth()
def home():
    print("welcome to home page")
    return "From home!"
@auth(auth_type="ldap")
def bbs():
    print("welcome to bbs page")
index()
print(home())     #调用home相当于调用wrapper
bbs()