装饰器

1.什么是装饰器

装饰器本质是函数, 其功能是, 装饰其他函数, 为其他函数添加附加功能

2. 应用场景

若我们的程序已经上线, 这时我们想为其添加新功能,原本是要修改源代码, 但是这有一定的风险,

这时我们可以编写装饰器(新功能函数),为其需要添加新功能的部分修饰

3 装饰器原则

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

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

 3.3 装饰器被装饰的函数来说是透明的

4. 实现装饰器的知识储备:

   4.1 函数即“变量”

   4.2 高阶函数 (什么是高阶函数)

        a. 把一个函数名 当作实参传递给另外一函数(在不修改被装饰的源代码的情况下,添加新功能)

        b. 返回值中包含 函数名 (不修改函数的调用方式)

   4.3 嵌套函数 (什么是嵌套函数)

         在一个函数体内,用def声明另外一个函数

    

# 嵌套函数
def foo():
    print("in the foo")
    def bar():
        print(" in the bar")
    bar() #bar 不能在外部调用, 因为它相当于一个局部变量
foo()


#下面是函数的调用,不是嵌套
def test1():
    test2()

test1()

5 装饰器示例

5.1 示例1

import time
def timmer(func): #test1 作为实参传入 timmer(test1)  func=test1
    def deco():
        start_time=time.time()
        time.sleep(1)
        func() #run test1()
        stop_time=time.time()
        print("the run time is %s "%(stop_time-start_time))
    return deco
@timmer #test1=timmer(test1)
def test1():
    print("in the test1")
#可以用Python 语法糖@加在需要被装饰的函数钱
#test1=timmer(test1) #timmer(test1)结果是其函数体-->return deco-->返回deco的内存地址
print(test1) #打印test1即 deco 的内存地址
test1()
View Code

先写一个高阶函数实现了“在不修改被装饰的源代码的情况下,添加新功能” ----把test1 这个函数名作为实参传入timmer这个函数

为了不改变其调用方式,我们又利用了嵌套函数,让其返回函数名 warrper

5.2 示例2 ---有参函数装饰器

import time

def timmer(func): # func=test2
    def deco(args): #增加text2(name)参数args
        start_time = time.time()
        time.sleep(3)
        func(args) #执行args
        stop_time = time.time()
        print("the func run time is %s"%(stop_time-start_time))
    return deco #返回deco的内存地址

@timmer
def test2(name):
    print("in the test2:",name)
test2('frank') # test2() = deco(),要想让test2()加参数,则需要给deco加参数
View Code

5.3 示例3 ---装饰任意函数的装饰器

import time

def timmer(func): 
    def deco(*args,**kwargs): #如果有增加参数,如果没有不加
        start_time = time.time()
        time.sleep(3)
        func(*args,**kwargs) #执行参数,如果有的话
        stop_time = time.time()
        print("the func run time is %s"%(stop_time-start_time))
    return deco #返回deco的内存地址

@timmer
def test2(name):
    print("in the test2:",name)
@timmer
def test1():
    print("in the test1")
test2('frank')# test2() = deco(),要想让test2()加参数,则需要给deco加参数
test1()
View Code

5.4 示例4---终极版---装饰器也带有参数

#!C:\Program Files\Python35/bin
# -*- conding: utf-8 -*-
#author: Frank
def auth(auth_type): #吸收第一层参数,装饰器的参数
    #print("auth func",auth_type)
    def out_warppage(func): #吸收第二层参数,将函数传入 func=home
        def warppage(*args,**kwargs):
            if auth_type == "local":
                user,pwd='frank','123'
                username = input("Username is :")
                password = input("Password is :")
                if username == user and password == pwd:
                    print("\033[32;1myou had login succesfull\033[0m")
                    res = func(*args,**kwargs) #run home(),index(),bbs()
                    return res
                else:
                    exit("\033[31;1m Invaild user/password\033[0m")
            else:
                print("Ldap 不会")
        return warppage
    return out_warppage


def index():
    print("welcom to index page")
@auth(auth_type="local") #当装饰器也带有参数时,我们需要在嵌套一层,
                        #装饰器的参数传给顶层函数作为实参
def home():
    print("welcom to home page")
    return "from home"
@auth(auth_type="ldap")
def bbs():
    print("weblcom to bbs")

index()
bbs()
home() #home=warapper
View Code

当语法糖也带有参数时, 我们需要在嵌套一层

a. 语法糖的参数传入顶层函数,加载以何种方式装饰(“local”  or "ldap")

b.被修饰的函数当作实参被传入第二层

c. 在a.b 两步都准备好之后,开始执行函数,这时a.b都加载进来了,便可以自如的做判断

 

posted @ 2017-03-26 23:24  FrankB  阅读(173)  评论(0编辑  收藏  举报