装饰器

1、定义:假设我们要增强一个函数的功能,比如,在函数调用前后自动打印日志,但又不希望改变这个函数的源代码,这种在代码运行期间动态增加功能且又不改变源代码的方式,成为装饰器(Decorator)。本质上,decorator就是一个返回函数的高阶函数

2、示例:

  

  如上图中的原函数为index(),我们通过装饰器为其增加了一个计算运行时间的功能,但是没有改变源代码,这就是为其增加了一个装饰器,装饰器的功能就是计时。

  关键点:@的语法,@timmer等同于进行了如下操作:index=timmer(index),函数名+()就是调用函数,一定要记住!!好多地方想不通原因就是在这里!

      思想就是把部内函数func()换成被装饰函数index()然后再运行闭包函数就好了(可能说的有点简单)

3、复杂一点的例子,代参数的,并且是用于多个参数不确定的函数的装饰器

import time
def timmer(func):
    def wrapper (*args,**kwargs):##注意注意*args和**kwargs
        start_time=time.time()
        func(*args,**kwargs)##注意注意*args和**kwargs
        stop_time=time.time()
        print("run time is %s"%(stop_time-start_time))
    return wrapper
@timmer##注意注意位于被装饰函数最上方,且单独占一行
def home(name):
    time.sleep(2)
    print("welcome to %s home page"%name)

@timmer
def auth(name,password):
    print(name,password)

@timmer
def tell():
    print('=======')
home('dragon')
auth('egon','123')
tell()

4、装饰用户认证功能

#现在是对index()函数增加了用户认证功能,源代码没有变
def auth2(auth_type): def auth(func): def wrapper(*args,**kwargs): if auth_type == 'file': name=input('username:') password=input('password:') if name=='zhejiangf4'and password == 'sbasb': print('auth successful') res=func(*args,**kwargs) return res else: print('auth error') elif auth_type =="sql": print("还他妈不会玩") return wrapper return auth @auth2(auth_type="file") #==>@auth==>index=auth(index),所以auth2作用就是传了一个值 def index(): print('Welcome to index page!') index()

5、再给上面的函数加一个时间模块

import time
def timmer(func):
    def wrapper():
        start_time=time.time()
        func()
        stop_time=time.time()
        print(stop_time-start_time)
    return wrapper
def auth2(auth_type):
    def auth(func):
        def wrapper(*args,**kwargs):
            if auth_type == 'file':
                name=input('username:')
                password=input('password:')
                if name=='zhejiangf4'and password == 'sbasb':
                    print('auth successful')
                    res=func(*args,**kwargs)
                    return res
                else:
                    print('auth error')
            elif auth_type =="sql":
                print("还他妈不会玩")
        return wrapper
    return auth
@timmer
@auth2(auth_type="file")#
def index():
    print('Welcome to index page!')
index()

  上面函数的运行原理需要细说一下

#先把大体的概念说一下:
# def aaa():#装饰函数
# @aaa
# def func():#被装饰函数
#     pass
#
# func=aaa(func)

# @ccc
# @bbb
# @aaa
# def func():
#     pass
#
# func=ccc(bbb(aaa(func)))

#
# @ccc('c')
# @bbb('b')
# @aaa('a')
# def func():
#     pass
#
# func=ccc('c')(bbb('b')(aaa('a')(func)))

#上边的例子是下边这个规律
#founc=bbb(aaa('a')(func))
#index=timmer(auth2(auth_type="list")(func))
#index=timmer(auth(func))
#index=timmer(wrapper_dixia)
#index=wrapper_shangbian
#index()=wrapper_shangbian()
#index()=wrapper_dixia()

6、eval函数:会把字符串里面的东西读出来执行,结果必须要赋值,不然砸电脑

m=input(">>:")
m=eval(m)
print(m,type(m))

>>:{"name":"agon"}
{'name': 'agon'} <class 'dict'>
>>:["agon"]
['agon'] <class 'list'>
>>:print(123)

7、给认证装饰器增加一个登陆后再次调用是免认证的功能(字典,只在内存中能行)

import time
current_login={'name':None,'login':False}#建立一个字典,字典存储登录状态
def timmer(func):
    def wrapper():
        start_time=time.time()
        func()
        stop_time=time.time()
        print('run time is %s'%(stop_time-start_time))
    return wrapper
def auth2(auth_type='file'):
    def auth(func):
        def wrapper(*args,**kwargs):
            if current_login['name'] and current_login['login']:#判断状态是否被激活,若激活直接执行函数结束
                res=func(*args,**kwargs)
                return res
            if auth_type == 'file':
                name = input('username:')
                password = input('password:')
                if name == 'zhejiangF4' and password == 'sb945':
                    print('auth successful')
                    res = func(*args,**kwargs)
                    current_login['name']=name#存储登录状态
                    current_login['login']=True
                    return res
                else:
                    print('auth error')
            elif auth_type == "sql":
                    print("haibuhui")
        return wrapper
    return auth
@timmer
@auth2(auth_type="file")
def index():
    print('welcome to index page')
@auth2("file")
def home():
    print("welcome to home page")

index()
home()#第一次执行index()函数是需要登录认证,但第二次执行home时就不需要再认证了

8、怎样在增加装饰器后还可以打印原函数的注释内容

import time
from functools import wraps#从函数工具中调用wraps模块
def timmer(func):
    @wraps(func)#它就可以让你打印出的index.__doc__编程原函数的"dashabi"而不是wrapper函数的"000"
    def wrapper(*args,**kwargs):
        '000'
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print('run time is %s'%(stop_time-start_time))
        return res
    return wrapper
@timmer
def index():
    "dashabi"
    print("from index")
index()
print(index.__doc__)

  

原文地址:https://www.cnblogs.com/wuyongqiang/p/6690004.html