# 装饰器
"""
1、准守开放封闭原则
对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
对修改封闭,意味着类一旦设计完成,就可以独立完成其工作,而不要对类进行任何修改。
2、python装饰器本质上就是一个函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外的功能,装饰器的返回值也是一个函数对象(函数的指针)。
装饰器函数的外部函数传入我要装饰的函数名字,返回经过修饰后函数的名字;内层函数(闭包)负责修饰被修饰函数
"""
# 通过下面几个示例解释装饰器的原理
# 示例1、函数增加功能
"""
1、我们有一个函数foo1,来sleep 2秒,然后打印内容
2、现在我们要在不修改foo1的情况下,打印代码执行时间
3、我们通过一个新的函数show_time,来调用foo1函数打印时间(通过对形参foo1赋值,foo1的值为函数foo1)。
实际上函数的调用方式发生了改变,原来是foo1(),现在是show_time(foo1),即实现了功能又增加了时间
4、但是实际上我们不应该修改调用方式(因为调用该功能的位置都需要修改代码)。
"""
import time
# sleep 2秒,并打印‘hello world’
def foo1():
time.sleep(2)
print('hello world')
# 通过show_time改变调用方式,实现打印执行时间
def show_time(foo1):
start_time = time.time()
foo1()
end_time = time.time()
print('执行时间{}'.format(end_time - start_time))
# 新的调用方式
show_time(foo1)
# 示例2、如果我们要想不改变原来的调用方式来增加功能,需要重新定义foo1函数
"""
1、写一个嵌套函数show_time1,将原来的show_time函数内容放到内部函数中。
2、foo2是一个闭包函数,因为引用了外部变量foo1,并且是一个内部函数。闭包函数是可以在外部调用的,详见闭包
3、我们将foo1重新赋值(闭包的调用方式2,详见闭包),这样就可以在不改变调用方式的前提下增加打印执行时间功能。
"""
def show_time1(foo1):
def foo2():
start_time = time.time()
foo1()
end_time = time.time()
print('执行时间{}'.format(end_time - start_time))
return foo2
# 变量赋值
foo1 = show_time1(foo1)
# 还用原来的方式调用
foo1()
# 示例3装饰器写法
"""
1、实际上面的示例2实现的功能就是装饰器,我们在下面的例子通过装饰器的写法来写一遍。
我们的功能函数(sleep 2秒,打印‘hello world’)为foo
打印执行时间的函数为Bar,里面的闭包函数为inter
在Bar函数中形参(变量)foo的值是被装饰的函数
2、在foo函数前面添加@Bar,表明这是一个装饰器。(注意:Bar函数定义要在foo函数之前)
3、实际上@Bar 完全等价于 foo = Bar(foo)
4、这样我们就通过一个装饰器实现了不改变原功能函数foo,以及不该变调用方法的前提下,增加了功能
"""
# 使用闭包函数,定义实现打印功能执行时间功能的代码
def bar(foo):
def inter():
start_time = time.time()
foo()
end_time = time.time()
print('执行时间{}'.format(end_time - start_time))
return inter
@bar # 声明装饰器 foo = Bar(foo)
def foo():
time.sleep(2)
print('hello world')
# 调用方法没有改变
foo()
# 总结
"""
1、装饰器就是通过闭包函数,帮我们实现在不修改原功能代码以及调用方式的前提下增加功能
2、上面三个示例分别实现的以下功能
示例1:增加了打印时间功能,但是调用方式放生了改变
示例2:实现了我们的要求,实质上就是装饰器的本质
示例3:通过装饰器的写法,实现了我们的要求
"""
# 在装饰器中给被装饰函数传递参数
"""
1、使用装饰器给被装饰的函数传递参数,将形参写到闭包函数中
2、在闭包函数中执行被装饰的函数时,将参数传递
"""
import time
# 装饰器函数,在闭包函数inter中接收参数,在调用函数foo中传递参数,变量foo的值是被装饰函数
def bar(foo):
def inter(a, b):
start_time = time.time()
foo(a, b)
end_time = time.time()
print('执行时间{}'.format(end_time - start_time))
return inter
@bar # 声明装饰器
def foo(a, b): # 功能函数
time.sleep(2)
print(a + b)
foo(3, 4)