装饰器

装饰器的主要功能:

在不改变函数调用方式的基础上在函数的前、后添加功能。

装饰器的固定格式:



#装饰器的本质 :闭包函数
#功能:就是在不改变原函数调用方式的情况下,在这个函数前后加上扩展功能
def timmer(func):
    def inner(*args,**kwargs):
        '''添加函数调用之前的扩展代码'''
        ret = func(*args,**kwargs)
        '''添加函数调用之后的扩展代码'''
        return ret
    return inner



语法:在被装饰对象的正上方的单独一行,使用@语法糖可以直接调用函数装饰器

设计模式

原则 开放封闭原则

#对扩展是开放的

#对修改是封闭的

1.对扩展是开放的

    为什么要对扩展开放呢? 

    我们必须允许代码扩展、添加新功能。

2.对修改是封闭的 

    为什么要对修改封闭呢? 

    我们对其进行了修改,很有可能影响其他已经在使用该函数的用户。

装饰器完美的遵循了这个开放封闭原则。



import time
def wrapper(func):  # 装饰
    def inner(*args, **kwargs):
        start = time.time()
        ret = func(*args, **kwargs)
        end = time.time()
        print(end - start)
        return ret
    return inner

@wrapper
def lll():
    time.sleep(0.1)
    print('hello')

lll()





编写装饰器,为多个函数加上认证的功能(用户的账号密码来源于文件),要求登录成功一次,后续的函数都无需再输入用户名和密码



login_dic={
"name":"None",
"passwd":"None",
 }
with open('passwd.txt', 'r+', encoding='utf-8') as f1:
    f2 = eval(f1.read())
def login(func):
    def inner(*args, **kwargs):
        '''判断用户名、密码是否在字典中'''
        if login_dic["name"]==f2["name"] and login_dic["passwd"]==f2["passwd"]:
            ret = func(*args, **kwargs)
            return ret
        else:
            name = input("请输入用户名:")
            passwd = input("请输入密码:")
            if name == f2['name'] and passwd == f2['passwd']:
                print("登陆成功")
                login_dic['name'] = name
                login_dic['passwd'] = passwd
                ret = func(*args, **kwargs)
                return ret
            else:
                print("输入有误,请重新输入")
    return inner
@login
def fun():
    print("123")
    print("456")
fun()
@login
def check():
    print("789")



 带参数的装饰器



def timer(func):
    def inner(a):
        start = time.time()
        func(a)
        print(time.time() - start)
    return inner

@timer
def func1(a):
    print(a)

func1(1)

装饰器——带参数的装饰器



import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func1 = timer(func1)
def func1(a,b):
    print('in func1')

@timer   #==> func2 = timer(func2)
def func2(a):
    print('in func2 and get a:%s'%(a))
    return 'fun2 over'

func1('aaaaaa','bbbbbb')
print(func2('aaaaaa'))

装饰器——成功hold住所有函数传参



import time
def timer(func):
    def inner(*args,**kwargs):
        start = time.time()
        re = func(*args,**kwargs)
        print(time.time() - start)
        return re
    return inner

@timer   #==> func2 = timer(func2)
def func2(a):
    print('in func2 and get a:%s'%(a))
    return 'fun2 over'

func2('aaaaaa','bbbbbb')
print(func2('aaaaaa'))

装饰器——带返回值的装饰器



def outer(flag):
    def timer(func):
        def inner(*args,**kwargs):
            if flag:
                print('''执行函数之前要做的''')
            re = func(*args,**kwargs)
            if flag:
                print('''执行函数之后要做的''')
            return re
        return inner
    return timer

@outer(False)
def func():
    print(111)

func()

带参数的装饰器格式



def wrapper1(func):
    def inner():
        print('wrapper1 ,before func')
        func()
        print('wrapper1 ,after func')
    return inner

def wrapper2(func):
    def inner():
        print('wrapper2 ,before func')
        func()
        print('wrapper2 ,after func')
    return inner

@wrapper2
@wrapper1
def f():
    print('in f')

f()

多个装饰器装饰同一个函数



实例



#带参数的装饰器 开关
# F = True

F = False
def outer(flag):
    def wrapper(func):
        def inner(*args,**kwargs):
            if flag:
                print('before')
                ret = func(*args,**kwargs)
                print('after')
            else:
                ret = func(*args, **kwargs)
            return ret
        return inner
    return wrapper

@outer(F)  #-->@wrapper  -->hahaha = wrapper(hahaha)  #-->hahaha == inner
def hahaha():
    print('hahaha')

@outer(F)   #shuangww = outer(shuangww)
def shuangww():
    print('shuangwaiwai')

shuangww()
hahaha()



'''
1.编写下载网页内容的函数,要求功能是:用户传入一个url,函数返回下载页面的结果
2.编写装饰器,实现缓存网页内容的功能:
具体:实现下载的页面存放于文件中,如果文件内有值(文件大小不为0),
就优先从文件中读取网页内容,否则,就去下载,然后存到文件中
'''
url_l = []
from urllib.request import urlopen

def get_cache(func):
    def inner(*args,**kwargs):
        url = args[0]
        filename = str(hash(url))
        if url in url_l:
            f = open(filename,'rb')
            ret = f.read()
        else:
            url_l.append(url)
            ret = func(*args, **kwargs)
            f = open(filename,'wb')
            f.write(ret)
        f.close()
        return ret
    return inner

@get_cache
def get(url):
    return urlopen(url).read()

print(get(''))
print(get(''))
print(get(''))
print(get(''))
print(get(''))