简单的装饰器
一、解释
给被装饰器添加新的功能。但必须要遵循开放封闭原则(a. 不改变被装饰对象的源代码。b. 不改变被装饰对象的调用方式。)
- 开发封闭原则:
- 开发:对扩展开放。
- 封闭:对修改封闭。
二、需求:统计index()
的运行时间。
- 方案一,常规方式。
# 统计index()的运行时间
import time
def index():
time.sleep(3) # cpu睡3秒
print("hello word!")
start = time.time()
index()
end = time.time()
print("index run time:%s"%(end - start))
>> hello word!
>> index run time: 3.001300096511841
- 方案二,运用装饰器。
- 第一步满足闭包,不改变原函数代码。
# 运用装饰器统计index()的运行时间
import time
def index():
time.sleep(3) # cpu睡3秒
print("hello word!")
def outter(func):
def get_time():
start = time.time()
func()
end = time.time()
print("index run time: %s" % (end - start))
return get_time
res = outter(index)
res()
>> hello word!
>> index run time: 3.001300096511841
需要注意的是,此方法源代码没有改变,但是改变了index()
的调用方式outter(index)
。
- 第二步,不改变调用方式,且给
index()
增加get_time()
函数的功能。
# 运用装饰器统计index()的运行时间
import time
def index():
time.sleep(3) # cpu睡3秒
print("hello word!")
def outter(func):
def get_time():
start = time.time()
func()
end = time.time()
print("index run time: %s" % (end - start))
return get_time
index = outter(index) # outter(最原始的index函数的内存地址)
print(index) # 此处的index指向get_time函数的内存地址。
index() # 与最原始的调用方式一致,只不过此处的index不是最开始的index了
- 第三步,提炼成装饰器。
# 运用装饰器统计index()的运行时间
import time
def outter(func):
def get_time():
start = time.time()
func()
end = time.time()
print("index run time: %s" % (end - start))
return get_time
# index = outter(index) # outter(最原始的index函数的内存地址)
# print(index) # 此处的index指向get_time函数的内存地址。
# index() # 与最原始的调用方式一致,只不过此处的index不是最开始的index了
@outter # 装饰器outter
def index():
time.sleep(3) # cpu睡3秒
print("hello word!")
index()
- 第四布,优化,增加不定参数。
# 运用装饰器统计index()的运行时间
import time
def outter(func):
def get_time(*args, **kwargs): # args 接收元组,kwargs 接收字典
start = time.time()
func(*args, **kwargs)
end = time.time()
print("index run time: %s" % (end - start))
return get_time
# index = outter(index) # outter(最原始的index函数的内存地址)
# print(index) # 此处的index指向get_time函数的内存地址。
# index() # 与最原始的调用方式一致,只不过此处的index不是最开始的index了
@outter
def index():
time.sleep(3) # cpu睡3秒
print("hello word!")
@outter
def index2(name):
time.sleep(2)
print("%s 是参数,有参函数" % (name))
index2("小明")
无参函数和有参函数都可以直接调用,函数可以接收任意数量的参数。
- 第五步,不改变原函数返回值。
# 1. 闭:定义在函数内部的函数。
# 2. 包:内部函数引用了外部函数作用域的名字。
# def outter():
# x = 111
# def inner():
# print(x)
# return inner
# res = outter()
# res()
# 给函数体传值的第一种方式
# def fun(x, y):
# if x > y:
# return x
# return y
#
#
# print(fun(1, 2))
# 给函数体传值的另一种方式--闭包
# def outter(x, y):
# # x = 1
# # y = 2
#
# def max():
# if x > y:
# return x
# return y
#
# return max()
#
#
# print(outter(1, 4))
# 统计index()的运行时间
# import time
# def index():
# time.sleep(3) # cpu睡3秒
# print("hello word!")
#
# start = time.time()
# index()
# end = time.time()
# print("index run time:%s"%(end - start))
# 运用装饰器统计index()的运行时间
import time
def outter(func):
def get_time(*args, **kwargs):
start = time.time()
res = func(*args, **kwargs)
end = time.time()
print("index run time: %s" % (end - start))
return res
return get_time
# index = outter(index) # outter(最原始的index函数的内存地址)
# print(index) # 此处的index指向get_time函数的内存地址。
# index() # 与最原始的调用方式一致,只不过此处的index不是最开始的index了
@outter # index = outter(index)
def index():
time.sleep(3) # cpu睡3秒
print("hello word!")
return "index"
@outter # index2 = outter(index2)
def index2(name):
time.sleep(2)
print("%s 是参数,有参函数" % (name))
return "index2"
print(index2("小明"))
>> 小明 是参数,有参函数
>> index run time: 2.0031635761260986
>> index2
注:语法糖@outter
会将它紧挨着的函数名当作第一个参数直接传入,直接调用。不改变调用,返回,传值。