p78-p80

装饰器

  • 开放封闭原则
  • 在不改变原函数以及代码调用方式的前提下,为其额外增加新的功能
import time
def func1():
    time.sleep(3)

def test(func):
    start_time = time.time()
    func()
    end_time=time.time()
    print(end_time-start_time)
    
test(func1) #这里改变了原函数的调用方式了,原先是函数名直接加括号,现在是函数名作为参数传到test函数
  • 就要用闭包
import time #改进一下
def func():
    time.sleep(3)

def test(func):
    def inner():
        start_time = time.time()
        func()
        end_time=time.time()
        print(end_time-start_time)
    return inner

ret = test(func) #ret 得到inner函数
ret()  #相当于inner()
  • 再改进
import time
def func1():
    time.sleep(3)

def test(func):
    def inner():
        start_time = time.time()
        func()
        end_time=time.time()
        print(end_time-start_time)
    return inner

func1 = test(func1) #这里还用原函数名 func
func1()  
  • 再改进 标准版
import time
def test(func):
    def inner():
        start_time = time.time()
        func()
        end_time=time.time()
        print(end_time-start_time)
    return inner

@test #装饰器 关键词函数前面加@
def func1():
    time.sleep(3)

func1()
  • 如果 func1 有返回值呢?
import time
def test(func):
    def inner():
        start_time = time.time()
        func()
        end_time=time.time()
        print(end_time-start_time)
    return inner

@test #装饰器 关键词函数前面加@
def func1():
    time.sleep(0.6)
    print('func1')
    return 1
a = func1() 
print(a) # 为啥我得到的是  None,因为最后执行的func1 函数实际是 inner函数,inner默认返回 None
  • 改进一下
import time
def test(func):
    def inner():
        start_time = time.time()
        a=func() #这里定义一个返回值给inner函数,最后返回出去
        end_time=time.time()
        print(end_time-start_time)
        return a #返回被装饰的函数的返回值
    return inner

@test #装饰器 关键词函数前面加@
def func1():
    time.sleep(0.6)
    print('func1')
    return 111
a = func1()
print(a)
  • 如果被装饰函数 func1 有参数呢
import time
def test(func):
    def inner(args): #func1 其实就是inner  ,所以inner 还要加参数
        start_time = time.time()
        a=func(args)
        end_time=time.time()
        print(end_time-start_time)
        return a
    return inner

@test #装饰器 关键词函数前面加@
def func1(arg1):
    time.sleep(0.6)
    print('func1')
    return 111
a = func1(5)
print(a) #return 111
  • 如果不确定有多少个参数呢
import time
def test(func):
    def inner(*args,**kwargs):
        start_time = time.time()
        a=func(*args,**kwargs) #涵盖所有函数的参数,*的打散和聚合 一个*存位置参数,两个存可迭代参数
        end_time=time.time()
        print(end_time-start_time)
        return a
    return inner  #这个就是标准装饰器

@test #装饰器 关键词函数前面加@
def func1(a):  #一个参数
    time.sleep(0.6)
    print('func1')
    return 111

@test
def calc(a,b): #2个参数
    time.sleep(0.5)
    return a+b
print(calc(5,6))  
  • 总结
#装饰器的结构如下
def wrapper(f): #wrapper 是装饰器名称,f是被装饰的函数
    def inner(*args,**kwargs):
        #这里是执行被装饰函数前,增加的额外功能
        ret = f(*args,**kwargs)
        #这里是执行被装饰函数后,增加的额外功能
        return ret 
    return inner
#用控制台方式模拟登陆网站访问功能,待完善
'''
1、进入控制台主程序,显示所有功能列表
    1、登陆
    2、注册
    3、访问个人主页(需要装饰器验证登陆状态,没有登陆,就讯运行登陆功能)简单显示一句话,再回到循环
    4、访问文章列表(需要装饰器验证登陆状态)
    5、访问评论列表(需要装饰器验证登陆状态)
2、按q或Q退出

'''
#存放网站功能列表
dict1 = [
    {'num':1,'content':'登陆','func':'login'},
    {'num':2,'content':'注册','func':'register'},
    {'num':3,'content':'访问个人主页','func':'user_info'},
    {'num':4,'content':'访问文章列表','func':'user_article'},
    {'num':5,'content':'访问评论列表','func':'user_comment'}
]
#存放登陆账号密码
dict2 = [
    {'name':'tom','pwd':'123456'},
    {'name':'jerry','pwd':'111111'},
]
dict3 = {'login_flag':False} #存放当前登陆账号状态

#装饰器
def test_login(f):
    def inner(*args,**kwargs):
        if dict3['login_flag']==False:
            if login()==False:return
        ret = f(*args,**kwargs)
        return ret
    return inner

#login
def login():
    c = 0
    while c < 3:
        c += 1
        name = input('Entry a name:')
        pwd = input('Entry a password:')
        for i in dict2:
            if name == i['name'] and pwd == i['pwd']:
                print('成功')
                dict3['login_flag']=True
                
                return
            else:
                continue
    return False

#register
def register():
    return True

#访问个人主页
@test_login
def user_info():
    print('我的主页')

#访问文章列表
@test_login
def user_article():
    print('我的文章列表')
    return True

#访问评论列表
@test_login
def user_comment():
    print('我的评论列表')

def main():
    while 1:
        for m in dict1:
            print(str(m['num'])+'.'+m['content'])
        num = input('请选择:')
        if num.upper()=='Q' :
            break
        elif num == '1':
            a = login()
            if a == False :
                print('超过3次')
                break
        elif num == '2':register()
        elif num == '3':user_info()
        elif num == '4':user_article()
        elif num == '5':user_comment()
        else:
            continue

main()
posted on 2020-07-13 18:15  94小渣渣  阅读(107)  评论(0编辑  收藏  举报