装饰器

装饰器

装饰器的本质:一个闭包函数
装饰器的功能:在不修改原函数及其调用方式的情况下对原函数功能进行扩展
装饰器的原则:开放封闭原则, 对扩展是开放的,对修改是封闭的

装饰器的固定格式

普通版

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

wrapers版

from functools import wraps

def deco(func):
    @wraps(func) #加在最内层函数正上方
    def wrapper(*args,kwargs):
        return func(*args,kwargs)
    return wrapper

装饰器的形成过程

import time


def func1(func):  #装饰器函数
    def inner():
        start = time.time()
        time.sleep(2)
        ret = func() #被装饰的函数
        end = time.time()
        print(end - start)
        return ret
    return inner


@func1  #语法糖 @装饰器函数名
def func2():  #被装饰的函数
    time.sleep(3)
    print("nihao")


func2()

完善一下上面那个装饰器

from functools import wraps


def demo(func):
    @wraps(func)
    def wrapper(*args, kwargs):
        return func(*args, kwargs)
    return wrapper


@demo
def index():
    '''
    小姐姐,我想你了!
    '''
    print("hello,world")


print(index.__doc__)
print(index.__name__)
装饰器完善

带参数的装饰器

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


@outer(False)
def func2():
    time.sleep(3)
    print("nihao")


func2()
带参数的装饰器

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

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()
多个装饰器装饰同一个函数

装饰器函数

装饰器函数—— 装饰器一定是闭包函数 装饰器的作用 : 在不改变原来函数的调用方式的情况下 在这个函数的前后添加新的功能 完美的符合了一个开发原则 :开放封闭原则 对扩展是开发的 对修改是封闭的 基础的装饰器

from functools import wraps


def wrapper(func):
    @wraps(func)
    def inner(*args, kwargs):
        '''在函数被调用之前添加的代码'''
        ret = func(*args, kwargs)   # func是被装饰的函数 在这里被调用
        '''在函数被调用之后添加的代码'''
        return ret
    return inner
    # 使用 —— @wrapper


@wrapper
def func():  # inner
    pass


func.__name__
View Code

带参数的装饰器

@wrapper -- > @warapper(argument)
三层嵌套函数
def outer(形参):
    def wrapper(func):
        def inner(*args,kwargs):
            '''在函数被调用之前添加的代码'''
            ret = func(*args,kwargs)   # func是被装饰的函数 在这里被调用
            '''在函数被调用之后添加的代码'''
            return ret
        return inner
    return wrapper
@outer(True)
def func():
    pass
View Code

多个装饰器装饰一个函数

def wrapper1(func):
        @wraps(func)
        def inner(*args,kwargs):
            print('before 1')
            print('')
            ret = func(*args,kwargs)   # func是被装饰的函数 在这里被调用
            '''在函数被调用之后添加的代码'''
            return ret
def wrapper2(func):
    @wraps(func)
    def inner(*args,kwargs):
        print('before 2')
        ret = func(*args,kwargs)   # func是被装饰的函数 在这里被调用
        '''在函数被调用之后添加的代码'''
        return ret
@wrapper1
@wrapper2
def func():
    print('111')
View Code

装饰器进阶

functools.wraps

from functools import wraps


def wrapper(func):
    @wraps(func)
    def inner(*args, kwargs):
        print("在被装饰的函数执行之前做的事情")
        ret = func(*args, kwargs)
        print("再被装饰的函数执行之后做的事情")
        return ret
    return inner


@wrapper
def holiday(day):
    '''
    这是一个放假通知
    '''
    print("全体放假%s天" % day)
    return "好开心"


print(holiday.__name__)
print(holiday.__doc__)
ret = holiday(3)
print(ret)
View Code

带参数的装饰器

import time
FLAGE = False
def timmer_out(flag):
    def timmer(func):
        def inner(*args,kwargs):
            if flag:
                start = time.time()
                ret = func(*args,kwargs)
                end = time.time()
                print(end-start)
                return ret
            else:
                ret = func(*args, kwargs)
                return ret
        return inner
    return timmer
# timmer = timmer_out(FLAGE)
@timmer_out(FLAGE)    #wahaha = timmer(wahaha)
def wahaha():
    time.sleep(0.1)
    print('wahahahahahaha')

@timmer_out(FLAGE)
def erguotou():
    time.sleep(0.1)
    print('erguotoutoutou')

wahaha()
erguotou()
View Code

多个装饰器装饰一个函数

def wrapper1(func):
    def inner1():
        print('wrapper1 ,before func')
        ret = func()
        print('wrapper1 ,after func')
        return ret
    return inner1

def wrapper2(func):
    def inner2():
        print('wrapper2 ,before func')
        ret = func()
        print('wrapper2 ,after func')
        return ret
    return inner2

def wrapper3(func):
    def inner3():
        print('wrapper3 ,before func')
        ret = func()
        print('wrapper3 ,after func')
        return ret
    return inner3

@wrapper3
@wrapper2
@wrapper1
def f():
    print('in f')
    return '哈哈哈'

print(f())
View Code

装饰器小练习

def wrapper(func): #qqxing
    def inner(*args, kwargs):
        ret = func(*args, kwargs) #被装饰的函数
        return ret
    return inner


@wrapper  #qqxing = wrapper(qqxing)
def qqxing():
    print(123)


qqxing()
View Code
def qqxing():
    '''
    ni hao ,Bye
    '''
    print("哈哈哈!")


print(qqxing.__name__) #查看字符串格式的函数名
print(qqxing.__doc__)  #查看document
qqxing()
View Code
def wrapper(func):
    def inner(*args,kwargs):
        print('在被装饰的函数执行之前做的事')
        ret = func(*args,kwargs)
        print('在被装饰的函数执行之后做的事')
        return ret
    return inner

@wrapper   #holiday = wrapper(holiday)
def holiday(day):
    print('全体放假%s天'%day)
    return '好开心'

ret = holiday(3)
print(ret)
View Code
def outer(*args):
    print(args)
    print(*args)
    def inner(*args):
        print('inner : ',args)
    inner(*args)


outer(1,2,3,4)   #==outer(*[1,2,3,4])  #==outer(*(1,2,3,4))
View Code

装饰器作业

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

FLAG = False
def login(func):
    def inner(*args,kwargs):
        global FLAG
        '''登录程序'''
        if FLAG:
            ret = func(*args, kwargs)  # func是被装饰的函数
            return ret
        else:
            username = input('username : ')
            password = input('password : ')
            if username == 'boss_gold' and password == '22222':
                FLAG = True
                ret = func(*args,kwargs)      #func是被装饰的函数
                return ret
            else:
                print('登录失败')
    return inner

@login
def shoplist_add():
    print('增加一件物品')

@login
def shoplist_del():
    print('删除一件物品')

shoplist_add()
shoplist_del()
View Code

2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件

def log(func):
    def inner(*args,kwargs):
        with open('log','a',encoding='utf-8') as f:
            f.write(func.__name__+'\n')
        ret = func(*args,kwargs)
        return ret
    return inner

@log
def shoplist_add():
    print('增加一件物品')

@log
def shoplist_del():
    print('删除一件物品')

shoplist_add()
shoplist_del()
shoplist_del()
shoplist_del()
shoplist_del()
shoplist_del()
View Code

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

import os 
from urllib.request import urlopen
def cache(func):
    def inner(*args,kwargs):
        if os.path.getsize('web_cache'):
            with open('web_cache','rb') as f:
                return f.read()
        ret = func(*args,kwargs)  #get()
        with open('web_cache','wb') as f:
            f.write(b'*'+ret)
        return ret
    return inner

@cache
def get(url):
    code = urlopen(url).read()
    return code


# {'网址':"文件名"}
ret = get('http://www.baidu.com')
print(ret)
ret = get('http://www.baidu.com')
print(ret)
ret = get('http://www.baidu.com')
print(ret)
View Code

你可能感兴趣的:(装饰器)