装饰器高潮

一、概述

我们之前介绍了大幅片的内容,感觉跟装饰器半毛钱关系都没有,其实不然,我们分别详细阐述了高阶函数和内置函数,下面我们就来讲讲什么是真正的装饰器。

 

二、装饰器定义

首先装饰器实现的条件:高阶函数+嵌套函数 =》装饰器

1、定义

import time                                                                   
                                                                              
def timer(func):    #func = sample_1   timer(sample_1)                        
    def deco():                                                               
        start_time = time.time()                                              
        func()      #run sample_1()                                           
        stop_time = time.time()                                               
        print("the func time is %s" %(stop_time-start_time))                  
    return deco                                                               
                                                                              
                                                                              
@timer  #timer来装饰sample_1                                                     
def sample_1():    #相当于 sample_1 = timer(sample_1)                            
    time.sleep(3)                                                             
    print('it is sample_1')                                                   
                                                                              
                                                                              
#直接执行函数                                                                       
sample_1()                                                                    
#输出结果
it is sample_1
the func time is 3.0023279190063477

执行步骤:

  1. 执行timer函数,timer(sample_1) 返回值赋值给sample_1变量,即sample_1=timer(sample_1)
  2. 此时的sample_1的值是执行timer函数返回值deco,即sample_1=deco
  3. 所以执行sample_1,其实就是执行的是deco函数,sample_1()其实就是执行deco()函数。

2、执行函数带参数

我们先来试试,如果被装饰的函数需要传入参数怎么办?

import time

def timer(func):    #func = sample_X   timer(sample_X)
    def deco():
        start_time = time.time()
        func()      #run sample_1()
        stop_time = time.time()
        print("the func time is %s" %(stop_time-start_time))
    return deco

@timer
def sample_2(name,age):    #相当于 sample_2 = timer(sample_2)
    time.sleep(3)
    print("name is %s,age is %s" %(name,age))
#直接执行函数
sample_2('seven_day',30)

#输出结果

Traceback (most recent call last):
File "/Users/lin/Desktop/lin/py/装饰器/前奏1.py", line 25, in <module>
sample_2('seven_day',30)
TypeError: deco() takes 0 positional arguments but 2 were given

很显然是错误的,错误的。因为这边执行的test2函数其实就是执行的deco函数,deco函数体内的func()其实就是执行sample_2函数,但是,sample_2需要传入name和age两个参数,所以报错。那怎么解决呢?我们只能传入参数了,但是你又不能确定传入几个参数,所以我们只能用非固定参数传参。代码如下:

import time

def timer(func):    #func = sample_X   timer(sample_X)
    def deco(*args,**kwargs): #传入非固定参数
        start_time = time.time()
        func(*args,**kwargs)   #传入非固定参数      #run sample_1()
        stop_time = time.time()
        print("the func time is %s" %(stop_time-start_time))
    return deco


@timer  #timer来装饰sample_1
def sample_1():    #相当于 sample_1 = timer(sample_1)
    time.sleep(3)
    print('it is sample_1')

@timer
def sample_2(name,age):    #相当于 sample_2 = timer(sample_2)
    time.sleep(3)
    print("name is %s,age is %s" %(name,age))
#直接执行函数
sample_1()
sample_2('seven_day',30)
#输出结果

it is sample_1
the func time is 3.00357723236084
name is seven_day,age is 30
the func time is 3.001821994781494

 

三、执行函数有返回值

上面的例子,被调用的函数都没有返回值,那如果,我们被调函数有返回值,该如何做呢?

user,passwd = "seven",'123'
def auth(auth_type):    #传递装饰器的参数
    print("auth func",auth_type)
    def outer_wrapper(func):   # 将被装饰的函数作为参数传递进来
        def wrapper(*args, **kwargs):  # 将被装饰的函数作为参数传递进来
            print("auth wrapper age",*args,**kwargs)

            username = input("请输入用户名:").strip()
            password = input("请输入密码:").strip()

            if auth_type == "local":
                if user == username and passwd == password:
                    print("\033[32;1m user has passed authentication\033[0m")
                    res = func(*args, **kwargs)
                    print("----after authentication----")
                    return res
                else:
                    exit("\033[31;1mIvalid username or password\033[0m")
            elif auth_type == "ldap":
                print("ldap")

        return wrapper
    return outer_wrapper


def index():
    print("welcome to index page")
@auth(auth_type="local")    #带参数装饰器
def home():
    print("welcome to home page")
    return "from home"
@auth(auth_type="ldap")    #带参数装饰器
def bbs():
    print("welcome to bbs page")


index()
home()
bbs()

重上面的例子可以看出,执行步骤:

  1. outer_wrapper = auth(auth_type="local")
  2. home = outer_wrapper(home)
  3. home()

所以这个函数的作用分别是:

  1. auth(auth_type) 传递装饰器的参数
  2. outer_wrapper(func) 把函数当做实参传递进来
  3. wrapper(*args,**kwargs) 真正执行装饰的函数
posted @ 2017-08-12 23:16  七天&七天  阅读(125)  评论(0编辑  收藏  举报