python_装饰器

# 装饰器形成的过程 : 最简单的装饰器 有返回值得  有一个参数  万能参数
# 装饰器的作用
# 原则 :开放封闭原则
# 语法糖:@装饰函数名
# 装饰器的固定模式

import time
# time.time()  # 获取当前时间
# time.sleep() # 等待
# 装饰带参数的装饰器
def timer(f):   # 装饰函数
    def inner(*args,**kwargs):
        start = time.time()
        ret = f(*args,**kwargs)  # 被装饰函数
        end = time.time()
        print(end-start)
        return ret
    return inner
@timer         # 语法糖 @装饰器函数名  在被装饰函数的上面
def func(a):    #  被装饰的函数
    time.sleep(0.1)
    print('哈哈哈')
    return 'hello'


# func = timer()

ret = func()  # inner
print(ret)



# 装饰器的作用 不想修改函数的调用方式 但是还想再原来的函数前后添加功能
# timmer 就是一个装饰函数,只是对一个函数 有一些装饰作用

# 原则:开放封闭原则
# 开放:对扩展是开放的
# 封闭:对修改是封闭的

# 装饰器的固定模式
def wrapper(f):   # 装饰器函数,f是被装饰的函数
    def inner(*args,**kwargs):
        '''在被装饰函数之前要做的事'''
        ret = f(*args,**kwargs)    # 被装饰的函数
        '''在被装饰函数之后要做的事'''
        return ret
    return inner

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

ret = func_name
装饰器的进阶
# functools.wraps
# 带参数的装饰器
# 多个装饰器装饰同一个函数
wraps

def wahaha():
    '''打印这个函数'''
    pass
print(wahaha.__name__)  # 查看字符串格式函数名
print(wahaha.__doc__) # 查看函数注释

from functools import wraps   # 引入wraps,全局被装饰的函数也能使用
def wrapper(f):
    @wraps(f)   # 在这里装饰inner  作用保留原有函数的名称和docstring
    def inner(*args,**kwargs):
        '''在被装饰函数之前要做的事'''
        ret = f(*args,**kwargs)
        '''在被装饰函数之后要做的事'''
        return ret
    return inner

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

ret = func_name

print(func_name.__name__)
# 带参数的装饰器
import time    # 引入时间模块
flage = False   # 定义一个全局变量
def timer_out(flage):   装饰器函数外面在裹一个函数
    def timer(func):
        def inner(*args,**kwargs):
            if flage:         # 加个判断
                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 timer

@timer_out(flage)   #这里要明白 timer_out(flage) = timer ,所以还是@timer  
def wahaha():
    time.sleep(0.1)
    print('hehei')

@timer_out(flage)
def hel():
    time.sleep(0.1)
    print('lalala')

wahaha()
hel()
# 多个装饰器装饰一个函数
def wrapper1(func):
    def inner1():
        print('wrapperl,before func')
        func()
        print('wrapper1 after func')
    return inner1

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

@wrapper1
@wrapper2       #距离最近的先执行,这个要好好理解执行变化
def f():
    print('in f')
f()
# 1.编写装饰器,为多个函数加上认证的功能(用户的账户密码来源于文件)要求登录成功一次,后续的函数都无需再输入用户名和密码
flat = False   #定义一个全局变量 好像其他也能代替
def login(func):
    def inner(*args,**kwargs):
        global flat     # 这里不能用nonlocal声明
        '''先登录程序'''
        if flat:
            ret = func(*args,**kwargs)
            return ret
        else:
            username = input('username:')
            password = input('password:')
            if username == 'boss' and password == '666666':
                flat = True
                ret = func(*args,**kwargs)
                return ret
            else:
                print('登录失败')
    return inner

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

shoplist_add()
shoplist_del()
# 2.编写装饰器,为多个函数加上记录调用功能,要求每次调用函数都将被调用的函数名称写入文件
def log(func):
    def inner(*args,**kwargs):
        with open('log','a',encoding='utf-8') as f:
            f.write(func.__name__+'
')
        ret = func(*args,**kwargs)
        return ret
    return inner

@log
def shoplist_add():
    print('增加一件物品')
@log
def shoplist_del():
    print('删除一件物品')
# 进阶作业(选做)
# 1.编写下载网页内容的函数,要求功能是:用户传入一个URL,函数返回下载页面的结果
from urllib.request import urlopen
def get(url):
    code = urlopen(url).read
    return code
ret =get('http://www.baidu.com')
print(ret)
#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)
        with open('web_cache','wb') as f:
            f.write(ret)
        return ret
    return inner

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

ret = get('http://www.baidu.com')
print(ret)
原文地址:https://www.cnblogs.com/niunai/p/10553947.html