周四,晴,记录生活分享点滴
参考博客:https://www.cnblogs.com/yuanchenqi/articles/5830025.html
推荐阅读:https://www.runoob.com/w3cnote/python-func-decorators.html
Python版本:3.5
装饰器前期
作用域
https://www.cnblogs.com/chungzhao/p/12973075.html 5.0
函数即对象
函数对象的调用比其它对象多了一个(),foo,bar与a,b一样都是个变量名
只有函数加载到内存才可以被调用
1. 可以被赋给其他变量
def foo(): print('foo') bar=foo bar() foo() print(id(foo),id(bar)) #4321123592 4321123592
2. 可以被定义在另外一个函数内(作为参数&作为返回值)
# *******函数名作为参数********** def foo(func): print('foo') func() def bar(): print('bar') foo(bar) # foo bar # *******函数名作为返回值********* def foo(): print('foo') return bar def bar(): print('bar') b = foo() b() # foo bar
函数的嵌套以及闭包
嵌套函数
name = "Chung" def change_name(): name = "Chung2" def change_name2(): name = "Chung3" print("第3层打印", name) ## 第3层打印 Chung3 change_name2() # 调用内层函数 print("第2层打印", name) ## 第2层打印 Chung2 change_name() print("最外层打印", name) ## 最外层打印 Chung # 各个 print 与 函数 位于同一级别
闭包函数
https://blog.csdn.net/weixin_44141532/article/details/87116038
闭包格式:
def 外层函数(参数): def 内层函数(): print("内层函数执行", 参数) return 内层函数 内层函数的引用 = 外层函数("传入参数") 内层函数的引用()
闭包举例:
def func(a, b): #1.外函数func有接收参数 a=2,b=3 def line(x): #2.内函数line接收参数x=5 return a * x - b #3.在内函数体中计算了a*x-b 即 2×5-3的值作为返回值 return line #4.外函数返回内函数的引用(这里的引用指的是内函数line在内存中的起始地址,即第二、三行) #5.最终调用内函数line()得到返回值7 line = func(2, 3) print(line(5)) # 7
小结:闭包的核心是在返回时的引用,引用的是自己里面的那一层,这一层在内存中。
装饰器概念
作用
装饰器可以让其他函数在不需要修改代码的前提下增加额外的功能,抽离出大量与函数功能本身无关的雷同代码并继续重用。
简要概括是为已经存在的对象添加额外的功能
返回值
装饰器的返回值也是一个函数对象
应用场景
经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等应用场景
简单装饰器
常规
通过 show_time(foo) 返回一个函数对象,这个函数对象内是核心业务(干活儿的)函数:执行func()与装饰函数时间计算
import time # ------------------------------------- # def show_time(func): def wrapper(): start_time=time.time() func() end_time=time.time() print('spend %s'%(end_time-start_time)) return wrapper # ------上面是装饰器函数,下面是功能函数----- # def foo(): print('hello foo') time.sleep(3) # -------------------------------------- # foo=show_time(foo) foo()
@ 语法糖
避免再一次赋值操作
省去foo=show_time(foo)或者bar = show_time(bar)这句,直接调用foo()或者bar()得到结果
import time def show_time(func): def wrapper(): start_time=time.time() func() end_time=time.time() print('spend %s'%(end_time-start_time)) return wrapper # wrapper为闭包函数 @show_time #foo=show_time(foo) def foo(): print('hello foo') time.sleep(3) @show_time #bar=show_time(bar) def bar(): print('in the bar') time.sleep(2) foo() print('***********') bar()
@show_time的作用是指在执行业务逻辑foo()时,执行的代码由粉框部分转到蓝框部分
被装饰函数的参数
给功能函数加参数
#***********不定长参数************** import time def show_time(func): def wrapper(*args,**kwargs): start_time=time.time() func(*args,**kwargs) end_time=time.time() print('spend %s'%(end_time-start_time)) return wrapper @show_time #add=show_time(add) def add(*args,**kwargs): # 给功能函数加参数 time.sleep(1) sum=0 for i in args: sum+=i print(sum) add(2,4,8,9)
带参数的装饰器
在上面的装饰器调用中,比如@show_time,该装饰器唯一的参数就是执行业务的函数
装饰器的语法允许我们在调用时,提供其它参数,比如@decorator(a),可以继续添加参数来实现更多的功能
import time def logger(flag=''): # 多增加了一个函数 = 多增加了一个功能:打印'文件目录' def show_time(f): def inner(*x, **y): start = time.time() f(*x, **y) end = time.time() print('spend %s' % (end - start)) if flag == 'true': print('日志记录') #新增的功能 return inner return show_time @logger('true') # 与if flag == 'true'相对应 def add(*a, **b): time.sleep(1) sums=0 for i in a: sums += i print(sums) add(1, 2, 5) #8 spend 1.0103797912597656 日志记录 @logger('') # 如果没有输入true,不会打印日志记录 def bar(): time.sleep(2) print('hello') bar() # hello spend 2.008728265762329