函数装饰器

装饰器
  什么是装饰器
  器,指的就一种种工具,列如生活中的,刮毛器
  装饰,指的是给某个已存在的对象添加装饰品
  装饰器的目的是为了给这个被装饰对象,提价新功能或者说,增加某种能力
  在程序中工具就是函数
  如此一来,装饰器指也就是一个函数,被装饰者也是一个函数
  总结:装饰器就是用一个函数去扩展另一个已存在的函数的功能
  扩展是对于一个应用程序来水非常重要的能力,任何应用程序都需要扩展,于是出现了开闭原则
  开闭原则
    对修改关闭,对扩展开放
    不允许修改源代码以及调方式
  装饰器就是一种可以保证不修改源代码,也不修改调用方式,还能给函数增加新功能的方式
需求:目前已有一个函数,其功能是从服务器下载一个文件,需求要为这个函数统计下载耗时
# import time
# 现有的已经投入使用的下载功能
# def download(filepath):
# print('开始下载%s....'%filepath)
# time.sleep(3)
# print('%s下载完成'%filepath)
# return '123'
# 现有的已经投入使用的上传功能
# def upload():
# print('开始上传。。。')
# time.sleep(3)
# print('上传完成。。。')
# download('毒液')
#测试1
# def download():
# boot_time=time.time()
# print('开始下载毒液。。。')
# time.sleep(3)
# print('毒液下载完成。。。')
# print('耗时:',time.time()-boot_time)
# download()
# 测试2
# boot_time=time.time()
# download()
# print('耗时:',time.time()-boot_time)
# 测试3
# def outer(func):
# def run_time(*args,**kwargs):
# boot_time=time.time()
# res=func(*args,**kwargs)
# print('耗时:', time.time() - boot_time)
# 修改了调用方式
# run_time(download)
# run_time(upload)
# 测试4
# def outer(func):
# def run_time(*args,**kwargs):
# boot_time=time.time()
# res=func(*args,**kwargs)
# print('耗时:', time.time() - boot_time)
# return res#把原始函数的执行结果 再交给调用者
# return run_time
# print(download)
# # 修改了调用方式
# download=outer(download)#res is run_time
# movie=download('大电影。。。')
# print(movie)
#
# upload=outer(upload)
# upload()
# print(download)
# 统计时间
# boot_time=time.time()
# print(boot_time)
# for i in range(10):
# print('hello')
# print(time.time()-boot_time)
装饰器的模板
# def download():
# pass
# def outer(func):
# def wrapper():
# print('扩展的新功能')
# func()
# print('扩展的新功能')
# return wrapper
# import time
# # 原始函数
# def test():
# print('test run ')
# 记录执行时间的装饰器
# def outer(func):
# def wrapper():
# '''
# 新功能
# :return:
# '''
# print('时间:',time.time(),'run:',func)
# func()
# return wrapper
# test=outer(test)
# test()
装饰器的语法糖
  语法糖
就是一种简便写法,使你的语法更简洁
提供输出日记(日志 什么时候干了什么事)功能
# import time
# # 原始函数
# def test():
# print('test run ')
# 记录执行时间的装饰器
# def outer(func):
# def wrapper():
# '''
# 新功能
# :return:
# '''
# print('时间:',time.time(),'run:',func)
# func()
# return wrapper
# test=outer(test)
# test()
import time
def logger(func):
def wrapper(*args,**kwargs):
print('时间:%s func:%s' %(time.time(),func.__name__))
res=func(*args,**kwargs)
return res
return wrapper
#该语法就可以帮我们完成对原始函数的伪装
# 注意1.必须写在被装饰函数的正上方
# 注意2.在开发时装饰器必须写在被装饰器函数之上
@logger #login =login(login)
def login():
print('登陆成功...')
login()
1.无参装饰器
import time
def download():
print('download run')
def outer(func):
def run_time(*args,**kwargs):#是为了让装饰器函数能接受任何形式任何长度的参数
boot_time=time.time()
res=func(*args,**kwargs)#将参数子啊原模原样交给被装饰者
print('耗时:',time.time()-boot_time)
return res#把原函数的执行结果 再交给调用者
return run_time
download=outer(download)
# 使用者
download()
同时叠加多个装饰器
import time
# 装饰器1
def logger(func):
def wrapper(*args,**kwargs):
print('时间:%s func:%s' %(time.time(),func.__name__))
res=func(*args,**kwargs)
return res
return wrapper
# 装饰器2
def timer(func):
def run_time(*args,**kwargs):
boot_time=time.time()
res=func(*args,**kwargs)#这是子啊执行原始的download函数也就是被装饰的函数
print('耗时:',time.time()-boot_time)
return res#把原始的函数的执行结果 再交给调用者
return run_time
# 该语法就可以帮我们完成对原始函数的伪装
# 注意1.必须写在被装饰函数的正上方
# 注意2.在开发时装饰器必须写在被装饰器函数之上
@time #logger=timer(logger)
@logger #login=logger(login)
def login():
print('登陆成功')
login()
# 在嵌套多个装饰器时,执行的顺序是从上往下依次调用,结束的顺序反过来,是从下往上
# 实际开发中 没什么用。。。
装饰器在购物车中的应用
is_login = False


# 判断是否登陆过的装饰器
def auth(func):
def wrapper(*args, **kwargs):
if is_login:
func(*args, **kwargs)
else:
print('还没有登陆过请先登陆。。')

return wrapper


def login():
global is_login
name = input('请输入用户名').strip()
pwd = input('请输入密码').strip()
if name == 'sss' and pwd == '123':
print('登录成功')
is_login = True


@auth
def shopping():
print('查看购物车。。。')


@auth
def collection():
print('查看收藏。。。')


def main():
while True:
funcs = {'1': login, '2': shopping, '3': collection}
print('''
1.登陆
2.查看购物车
3.查看收藏
''')
res = input('请输入编号').strip()
if res in funcs:
funcs[res]()
else:
print('输入有误')


main()
2.有参装饰器

需求: 提供一个用于输出日志的装饰器,可以指定日志的输出位置是打印到控制台或是文件中
import time


def outer(location):
def logger(func):
def wrapper(*args, **kwargs):
if location == 'cmd':
print("时间:%s func:%s" % (time.time(), func.__name__))
elif location == 'file':
with open('a.log', 'a', encoding='utf-8') as f:
f.write("时间:%s func:%s" % (time.time(), func.__name__))
else:
print('位置错误。。。。')
return func(*args, **kwargs)

return wrapper

return logger


# @logger
def test():
print('test run')
res = outer('file')
test = res(test)
test()

 

from functools import wraps
import time


def outer(location):
def logger(func):
@wraps(func)
def wrapper(*args, **kwargs):
'''
这是装饰器函数
:param args:
:param kwargs:
:return:
'''
if location == 'cmd':
print("时间:%s func:%s" % (time.time(), func.__name__))
elif location == 'file':
with open('a.log', 'a', encoding='utf-8') as f:
f.write("时间:%s func:%s" % (time.time(), func.__name__))
else:
print('位置错误。。。。。。')
return func(*args, **kwargs)

return wrapper

return logger


@outer('file') # logger=outer('file') test=logger(test)
def test():
'''
这是一个test函数
:return:
'''
print('test run')


# test()
print(test.__doc__)


def f1():
'''
这是个f1函数
:return:
'''


# __doc__可以获取文档注释内容
print(f1.__doc__)

原文地址:https://www.cnblogs.com/ShenJunHui6/p/10272694.html