第十四天

装饰器

"""
装饰器
"""
# AOP :面向切面,可以看成OOP的升级
# 在python中 装饰器相当于AOP的编程思想
# 闭包:在内部函数中访问外部函数的变量。外部函数中直接返回内部函数的名字
# (1)嵌套函数 (2)内部函数访问外部变量 (3) 外部函数return inner名字
# 闭包的例子
def outer():
x=1
def inner():
x=2
print(x)
return inner
inner_new=outer()
inner_new()
print(inner_new.__closure__)

一、 装饰器的基本原理
1. 背景例子
# 实现bill上下班打卡
def on_duty(name):
print("{}上班".format(name))
def off_duty(name):
print("{}下班了".format(name))
on_duty("bill")
off_duty("bill")

# 需求变更,要求在上下班打卡后,显示时间
from datetime import datetime
def on_duty(name):
print("{}上班了".format(name))
# check_in()
def off_duty(name):
print("{}下班了".format(name))
# check_in()
on_duty("bill")
off_duty("bill")

def check_in():
print(datetime.now())
def new_onduty(name):
on_duty(name)
check_in()
new_onduty("bill")

# 闭包
# 1. 希望调用的时候,方法名字还叫onduty 闭包返回的就是 函数的名字
# 2. 希望checkin 函数加到onduty的功能中 闭包中如果参数直接使用函数的名字
def on_duty(name):
print("{}上班了".format(name))
def off_duty(name):
print("{}下班了".format(name))

# 在闭包传入的参数中,名字应该是函数的名字,闭包外部函数可以装饰任何一个名字
def chekc_in(on_duty):
def inner(name):
on_duty(name)
print(datetime.now())
return inner
on_duty=check_in(on_duty)
on_duty("bill")
off_duty=check_in(on_duty)
off_duty("bill")

# 装饰器的定义:就是一个函数,专门在不改变原有函数的基础上,对原有函数进行扩充。(闭包思想)
"""
def decortor(原函数名):
return 新函数名
"""

# 装饰器解决
# 装饰器定义好之后,怎么使用?
"""
在需要装饰的函数上面[@装饰器函数的名字]相当于代替on_duty=check_in(on_duty)
想当于执行了
fun=decoartor(fun)

# 语法糖:能够使用特殊的语法来方便程序员调用的方式,都叫语法糖
"""
def check_in(fun):
def inner(name):
result=fun(name)
print(datetime.now())
return result
return inner
@check_in
def on_duty(name):
print("{}上班了".format(name))
@check_in
def off_duty(name):
print("{}下班了".format(name))

on_duty=chekc_in(on_duty)
on_duty("bill")
off_duty=chekc_in(off_duty)
off_duty("bill")

二、 装饰器的优化
# 对于参数的优化:使用万能参数作为装饰器内部函数的参数。
# 这样装饰器就可以应用到其他的功能函数上
def check_in(fun):
    def inner(*args,**kwargs):
        fun(*args,**kwargs)
        print(datetime.now())
    return inner
@chekc_in
def on_duty(name):
    print("{}上班了".format(name))
@chekc_in
def off_duty(name):
    print("{}下班了".format(name))

on_duty=chekc_in(on_duty)
on_duty("bill")
off_duty=chekc_in(off_duty)
off_duty("bill")

  

# 对于返回值也可以获得
def check_in(fun):
def inner(*args,**kwargs):
result=fun(*args,**kwargs)
print(datetime.now())
return result
return inner
@chekc_in
def on_duty(name):
print("{}上班了".format(name))
return "success"
result=on_duty("bill")
print(result)

三、 装饰器的叠加
"""
decorator1装饰fun,decorator2装饰decorator1修饰好的fun
@decorator2
@decorator1
def fun():
pass
"""
def record(fun):
def inner(*args,**kwargs):
result=fun(*args,**kwargs)
print( result+"dddd""向领导汇报工作")
return inner
# def check_in(fun):
# def inner(*args,**kwargs):
# result=fun(*args,**kwargs)
# print(datetime.now())
# return result
# return inner
@record
@check_in
def on_duty(name):
print("{}上班了".format(name))
return "success"
result=on_duty("bill")
print(result)

on_duty=check_in(on_duty)
on_duty=record(on_duty)
on_duty()

# 注意:装饰器,参数一定是固定,只能是被装饰的函数名,不能再加任何一个参数
def check_in(format):
def inner_check_in(fun):
def inner(*args,**kwargs):
fun(*args,**kwargs)
print(datetime.strftime(datetime.now(),format))
return inner
return inner_check_in
def record(fun):
def inner(*args,**kwargs):
fun(*args,**kwargs)
print("汇报工作")
return inner
@record
# 在装饰器调用时,可以传入参数,使用的时候,@语法糖(参数的值)
@check_in("%Y-%m-%d %H:%M:%S")
def on_duty(name):
print("{}上班了".format(name))
@record
@check_in("%Y-%m-%d %H:%M:%S")
def off_duty(name):
print("{}下班了".format(name))


on_duty("bill")
off_duty("bill")

四、 保留函数的元信息

# 因为我们的函数使用装饰器之后,名字、说明文档、注释,都被inner相关信息给覆盖了
# 可以使用functools.wraps
from functools import wraps
def check_in(fun):
@wraps(fun)
def inner(*args,**kwargs):
fun(*args,**kwargs)
print(datetime.now())
return inner
@check_in
def on_duty(name :str) -> None:
"""
这是一个上班的函数
"""
print("{}上班了".format(name))
@check_in
def off_duty(name):
print("{}下班了".format(name))

on_duty("bill")
# __name__可以返回函数的名字
print(on_duty.__name__)
print(on_duty.__doc__)
print(on_duty.__annotations__)

装饰器类 (类装饰器)
class CheckIn:
def __init__(self,fun):
self.fun=fun
def __call__(self, *args, **kwargs):
self.fun(*args, **kwargs)
print(datetime.now())
@CheckIn
def on_duty(name :str) -> None:
"""
这是一个上班的函数
"""
print("{}上班了".format(name))
# on_duty=CheckIn(on_duty)
on_duty("bill")

# 练习:实现一个对程序记录日志的功能

# 日志的信息:方法的名字、传入的参数,运行时间,得到返回值,当前的操作时间
# 思路: 日志装饰器函数,闭包,显示元信息
import time
def log(funname):
def inner(*args, **kwargs):
print("这是程序日志start")
# 传入的参数 *args,**kwargs
argsStr = []
if args:
argsStr.append("".join([str(i) for i in args]))
if kwargs:
argsStr.append("".join(["%s=%s" % (k, v) for k, v in kwargs.items()]))

opertime = datetime.now()
start = time.time()
result = funname(*args, **kwargs)
time.sleep(1)
end = time.time()
text = """
这是日志信息:
当前方法的名字是{}
当前方法传入的参数是{}
当前方法操作的时间是{};
当前方法执行的时间是{};
当前方法的返回值是{}

"""
fn = funname.__name__
print(text.format(fn, argsStr, opertime, end - start, result))
return result

猜你喜欢

转载自www.cnblogs.com/ztx695911088/p/9115020.html