29 Mar 18 函数 有参、无参装饰器

一、无参装饰器及其升级版
1 开放封闭原则
软件一旦上线后,就应该遵循开放封闭原则,即对修改源代码是封闭的,对功能的扩展是开放的。也就是说我们必须找到一种解决方案:能够在不修改一个功能源代码以及调用方式的前提下,为其加上新功能。
 
总结原则如下:
1、不修改源代码
2、不修改调用方式
目的:在遵循1和2原则的基础上扩展新功能
 
2、什么是装饰器?
器指的工具,装饰指的是为被装饰对象添加新功能。装饰器即在不修改被装饰对象源代码与调用方式的前提下,为被装饰器对象添加新功能。
 
装饰器与被装饰的对象均可以是任意可调用的对象
装饰器=》函数
被装饰的对象=》函数
 
3、给函数加上了功能,但改变了原代码
import time
 
def index():
    start_time=time.time()   #time.time()调的是1970年至现在一共过了多少秒
    time.sleep(3)
    print('welcome to index page')
    stop_time=time.time()
    print('run time is %s' %(stop_time-start_time))
 
index()
 
4. 没有把常用功能抽象成函数,需要反复输入
import time
 
def index():
    time.sleep(3)
    print('welcome to index page')
 
def home(name):
    time.sleep(5)
    print('welcome %s to home page' %name)
 
start_time=time.time()
index()
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
 
start_time=time.time()
home('egon')
stop_time = time.time()
print('run time is %s' % (stop_time - start_time))
 
5、修改了原函数的调用方式,即无法用index()的形式直接调用
import time
 
def index():
    time.sleep(3)
    print('welcome to index page')
 
def home(name):
    time.sleep(5)
    print('welcome %s to home page' %name)
 
def wrapper(func): #func=index
    start_time=time.time()
    func() #index()
    stop_time = time.time()
    print('run time is %s' % (stop_time - start_time))
 
wrapper(index) # 修改了原函数的调用方式
 
6、 初步解决了问题,但没有考虑到原参数带返回值,或带参数的情况
import time
 
def index():
    time.sleep(3)
    print('welcome to index page')
 
def outter(func): #func=最原始的index
    # func=最原始的index
    def wrapper():
        start_time=time.time()
        func()
        stop_time=time.time()
        print(stop_time-start_time)
    return wrapper
 
index=outter(index) # 新的index=wrapper
index() #wrapper()
 
7、 考虑了原参数带返回值或参数的问题,但每次都要加上index=timmer(index)
import time
 
def index():
    time.sleep(1)
    print('welcome to index page')
    return 122
 
def home(name):
    time.sleep(2)
    print('welcome %s to home page' %name)
 
#==============装饰器
def timmer(func):
    #func=最原始的home
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs) #调用最原始的home
        stop_time=time.time()
        print(stop_time-start_time)
        return res
    return wrapper
 
index=timmer(index) # 新的index=wrapper
home=timmer(home) #新的home=wrapper
# ==========================================
index()
home('egon')
 
无参装饰器模板
def outer(func):
    def inner(*args,**kwargs):
        res=func(*args,**kwargs)
        return res
    return inner
 
8、运用装饰器语法糖 @timmer #index=timmer(index)
@timmer必须放在原函数的正上方, 
timmer的函数体要放在@timmer之前
如果要用装饰器加@。。。,如果不用注释掉@
 
import time
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print(stop_time-start_time)
        return res
    return wrapper
 
@timmer #index=timmer(index)
def index():
    time.sleep(1)
    print('welcome to index page')
    return 122
 
@timmer # home=timmer(home)
def home(name):
    time.sleep(2)
    print('welcome %s to home page' %name)
 
index()
home('egon')
 
9、认证装饰器实现(另一个例子)
import time
current_user={
    'username':None,
    # 'login_time':None
}
 
def auth(func):
    # func=index
    def wrapper(*args,**kwargs):
        if current_user['username']:
            print('已经登陆过了')
            res=func(*args,**kwargs)
            return res
 
        uname=input('用户名>>: ').strip()
        pwd=input('密码>>: ').strip()
        if uname == 'egon' and pwd == '123':
            print('登陆成功')
            current_user['username']=uname
            res=func(*args,**kwargs)
            return res
        else:
            print('用户名或密码错误')
    return wrapper
 
@auth #index=auth(index)
def index():
    time.sleep(1)
    print('welcome to index page')
    return 122
 
@auth
def home(name):
    time.sleep(2)
    print('welcome %s to home page' %name)
 
index()
home('egon')
 
10、叠加多个装饰器,上面的装饰器作用为:下方装饰器+原函数
import time
current_user={
    'username':None,
    # 'login_time':None
}
 
def auth(func):
    # func=index
    def wrapper(*args,**kwargs):
        if current_user['username']:
            print('已经登陆过了')
            res=func(*args,**kwargs)
            return res
 
        uname=input('用户名>>: ').strip()
        pwd=input('密码>>: ').strip()
        if uname == 'egon' and pwd == '123':
            print('登陆成功')
            current_user['username']=uname
            res=func(*args,**kwargs)
            return res
        else:
            print('用户名或密码错误')
    return wrapper
 
def timmer(func):
    def wrapper(*args,**kwargs):
        start_time=time.time()
        res=func(*args,**kwargs)
        stop_time=time.time()
        print(stop_time-start_time)
        return res
    return wrapper
 
@timmer # timmer 统计的是auth+index的执行时间
@auth
def index():
    time.sleep(1)
    print('welcome to index page')
    return 122
 
index()
 
二、有参数的装饰器 #再包上一层,函数的参数可以为一个,也可为多个
import time
current_user={
    'username':None,
    # 'login_time':None
}
 
def auth(engine):
    # engine='file'
    def auth2(func):
        # func=index
        def wrapper(*args,**kwargs):
            if engine == 'file':
                if current_user['username']:
                    print('已经登陆过了')
                    res=func(*args,**kwargs)
                    return res
 
                uname=input('用户名>>: ').strip()
                pwd=input('密码>>: ').strip()
                if uname == 'egon' and pwd == '123':
                    print('登陆成功')
                    current_user['username']=uname
                    res=func(*args,**kwargs)
                    return res
                else:
                    print('用户名或密码错误')
            elif engine == 'mysql':
                print('基于MyQL的认证')
            elif engine == 'ldap':
                print('基于LDAP的认证')
        return wrapper
    return auth2
 
@auth('ldap') #@auth2 #index=auth2(index) #index=wrapper
def index():
    time.sleep(1)
    print('welcome to index page')
    return 122
 
index() # wrapper()
原文地址:https://www.cnblogs.com/zhangyaqian/p/py20180329.html