day4-装饰器

装饰器定义

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

装饰器实现过程

在不修改源代码的情况下,给test1,2附加功能:

import time

def test1():
     time.sleep(3)
     print("in the test1")

def test2():
     time.sleep(3)
     print("in the test2")

test1()
test2()

1.加入高阶函数

import time

def deco(func):
     start_time=time.time()
     func()
     stop_time=time.time()
     print("the func run time is %s" %(stop_time-start_time))

def test1():
     time.sleep(3)
     print("in the test1")

def test2():
     time.sleep(3)
     print("in the test2")

deco(test1)
deco(test2)

尝试1:我们要求不改变调用方式,使用高阶函数的第二种方式——>返回值中包含函数名

def deco(func):
     start_time=time.time()
     return func  #程序运行至此return语句停止
     stop_time=time.time()
     print("the func run time is %s" %(stop_time-start_time))
def test1():
     time.sleep(3)
     print("in the test1")

def test2():
     time.sleep(3)
     print("in the test2")
test1 = deco(test1)
test1 ()

test2 = deco(test2)
test2 ()
#输出
in the test1
in the test2

#没有改变源代码,没有改变调用方式,但是功能没有附加

2.加入嵌套函数

尝试2:因为尝试1没有附加功能,在这里我们加入了嵌套函数

import time

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

def test1():
     time.sleep(3)
     print("in the test1")

def test2():
     time.sleep(3)
     print("in the test2")

test1=timer(test1)
test1()  #---->实际上是在执行deco()
#输出
in the test1
the func run time is 3.0035839080810547

#当我们执行test1()时,除了执行了test1(),还附加了其他的功能

装饰器的调用

在Python中,它给我们通过另一种方式调用装饰器,想在哪个函数上附加功能,就在该函数的头部加上@timer

import time

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


@timer               
def test1():           #该函数调用装饰器,实现附加功能
     time.sleep(3)
     print("in the test1")

 
@timer  
def test2():
     time.sleep(3)
     print("in the test2")

 
test1()
test2()
#输出
in the test1
the func run time is 3.0037789344787598
in the test2
the func run time is 3.0018179416656494

1.执行函数带参数

如果我们要在test函数里面传参数的话,我们可以:

import time

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

 
@timer   #相当于test1=timer(test1),      test1()=deco()
def test1():
     time.sleep(3)
     print("in the test1")


@timer    #相当于test1=timer(test1),      test1()=deco()
def test2(name):
     time.sleep(3)
     print("in the test2")


test2(“dick”)    # 由于我们执行test2("dick")是执行deco(),所以我们要把一个参数传进去
#输出
in the test1: dick
the func run time is 3.0016181468963623

但是,我们装饰的函数是千奇百怪的,所以我们要把不止一个参数传进去,怎么办?

import time

def timer(func):   #timer(test2) func=test2
      def deco(*args,**kwargs):
            start_time=time.time()
            func(*args,**kwargs) #run test2()
            stop_time=time.time()
            print("the func run time is %s"%(stop_time-start_time))
      return deco

@timer     #相当于test1=timer(test1),      test1()=deco()
def test1():
      time.sleep(3)
      print("in the test1")

@timer     #相当于test1=timer(test1),      test1()=deco()
def test2(name,age):
      time.sleep(3)
      print("in the test2",name,age)

test1(“dick”,22)
test2()
#输出
in the test1: dick 22
the func run time is 3.001953125
in the test2
the func run time is 3.004183053970337

 最后,我们通过一个例子来验证一下:

import time

user,passwd="huwei","qawsed"
def auth(func):
      def wrapper(*args,**kwargs): #2
            username=input("Username:")
            password=input("Password:")
            if user==username and password==passwd:
               print("\033[32;1mUser has passed authenticate!\033[0m")
               func(*args,**kwargs)  #1  “from home”
            else:
               exit("\033[31;1mInvalid user name or password!\033[0m")
      return wrapper

def index():
      print("Welcome to index page")

@auth
def home():
      print("welcome to homepage")
      return"from home"

@auth
def bbs():
      print("bbs page")

index()
print(home())  #home()---->实际上是在执行#2处的wrapper()
bbs()
#输出
Welcome to index page
Username:huwei
Password:qawsed
User has passed authenticate!
welcome to home page
None  #home返回的结果不见了,我们虽然没有改变源代码和调用方式,但是在这里,代码的返回结果改变了,怎么办?

解析:说到底其实是,#1处的func()调用的是home(),#1处没有返回的func,所以#1处的func()执行结果没有传给任何变量.而调用home()其实是在调用#2处的wrapper(),那么wrapper()执行了,没有返回值,只有内存地址,当然为None

2.执行函数有返回值

所以在#1处我们做如下修改:

return  func(*args,**kwargs) 

#或赋给一个变量,如:
res = func(*args,**kwargs) 
print("=========")
return res

再看看我们的代码:

import time

user,passwd="huwei","qawsed"

def auth(func):
      def wrapper(*args,**kwargs): #2
           username=input("Username:")
           password=input("Password:")
           if user==username and password==passwd:
               print("\033[32;1mUser has passed authenticate!\033[0m")
               res = func(*args,**kwargs)
               print("=========")
               return res
           else:
               exit("\033[31;1mInvalid user name or password!\033[0m")
     return wrapper

def index():
     print("Welcome to index page")

@auth
def home():
     print("welcome to home page")
     return"from home"

@auth
def bbs():
      print("bbs page")

index()
print(home())  #home()----》实际上是在执行#2处的wrapper()
bbs()
#输出
Welcome to index page
Username:huwei
Password:qawsed
User has passed authenticate!
welcome to home page
from home

但是在现实情况中,认证方式会有多种,ssh key认证,ldap认证,本地认证等等,那如何实现?再加一个认证装饰器?

答:我们可以再加一层,同时print()参数,看看传入的究竟是什么?

3.带参数的装饰器

import time

user,passwd="huwei","qawsed"

def auth(func):#3
      print("auth func:",func) #4
      def out_wrapper():    #5 新加入的一层
            def wrapper(*args,**kwargs): #2
                  print("wrapper func args:",*args,**kwargs)
                  username=input("Username:")
                  password=input("Password:")

                  if user==username and password==passwd:
                        print("\033[32;1mUser has passed authenticate!\033[0m")
                        func(*args,**kwargs)  #1  “from home”
                 else:
                        exit("\033[31;1mInvalid user name or password!\033[0m")
           return wrapper
     return out_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("bbs page")

index()
home()
bbs()
#输出
    @auth(auth_type="local")
TypeError: auth() got an unexpected keyword argument 'auth_type'

根据输出结果,我们将#3和#4处改为auth_type

def auth(auth_type):#3
      print("auth func:",auth_type) #4
#输出
    @auth(auth_type="local")       #auth func: local    #可以看到验证方式已经传进来了
TypeError: out_wrapper() takes 0 positional arguments but 1 was given

刚刚我们的#3处的func移下来了被我们删除了,其实我们删除的func传到#5处了(整体往下移了一层),接着我们将func在#5处传进来加上

import time

user,passwd="huwei","qawsed"

def auth(auth_type):
      print("auth func:",auth_type)
      def out_wrapper(func):
            def wrapper(*args,**kwargs):
                  print("wrapper func args:",*args,**kwargs)
                  username=input("Username:")
                  password=input("Password:")

                  if user==username and password==passwd:
                        print("\033[32;1mUser has passed authenticate!\033[0m")
                        return func(*args,**kwargs)  #return func()相当于home()
                 else:
                        exit("\033[31;1mInvalid username or password!\033[0m")
            return wrapper
     return out_wrapper


def index():
      print("Welcome to index page")

@auth(auth_type="local")
def home(): #6 home = wrapper  ————>>>home()相当于wrapper(),当执行home()时,直接执行wrapper函数
      print("welcome to homepage")
return"from home"

@auth(auth_type="ldap")
def bbs():
      print("bbs page")
#输出
Auth func: local
Auth func: ldap
Welcome to index page
wrapper func args:
Username:huwei
Password:qawsed
User has passed authenticate!
welcome to home page
wrapper func args:
Username:huwei
Password:qawsed
User has passed authenticate!
bbs page

如果我需要根据不同的参数输入执行不同的验证方式,那么:

import time

user,passwd="huwei","qawsed"

def auth(auth_type):
     print("auth func:",auth_type)
     def out_wrapper(func):
         def wrapper(*args,**kwargs):
             print("wrapper func args:",*args,**kwargs)
             if auth_type=="local":
                username=input("Username:")
                password=input("Password:")
                if user==username and password==passwd:
                   print("\033[32;1mUser has passed authenticate!\033[0m")
                   return func(*args,**kwargs)
                else:
                   exit("\033[31;1mInvalid username or password!\033[0m")
             elif auth_type=="ldap":
                  print("Access LDAP server.......")
          return wrapper
   return out_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("bbs page")



index()
home()
bbs()
#输出
auth func: local
auth func: ldap
welcome to index page
wrapper func  args:
username:huwei
password:qawsed
user has passed authenticate!
welcome to home page
wrapper func args:
Access LDAP server.......
posted @ 2017-07-21 15:42  Mr.hu  阅读(136)  评论(0编辑  收藏  举报