装饰器
1.装饰器(函数):
装饰器本质上是一个Python函数,它可以让其他函数在不需要做任何代码变动的前提下增加额外功能,装饰器的返回值也是一个函数对象。它经常用于有切面需求的场景,比如:插入日志、性能测试、事务处理、缓存、权限校验等场景。装饰器是解决这类问题的绝佳设计,有了装饰器,我们就可以抽离出大量与函数功能本身无关的雷同代码并继续重用。概括的讲,装饰器的作用就是为已经存在的对象添加额外的功能。
装饰器知识点:
1.函数的作用域原则:
# 函数作用域查找顺序:局部变量》嵌套变量》全局变量》全局变量》内置变量 x = 10 # 全局变量 def f(): a = 5 # 嵌套作用域 def inner(): count = 7 # 局部变量 print(a) return 1
return inner() print(f())
2.高阶函数:高阶函数有两个条件,满足其中一个都叫高阶函数
2.1 函数名可以作为参数输入
2.2函数名还可以作为返回值
内存情况示意图

3.闭包
闭包其实就是一种现象
闭包的作用:满足闭包条件的函数就可以脱离局部作用域的环境从而达到被外包调用的作用
关于闭包:闭包=内部函数+定义函数时的环境
def outer():
x = 10 def inner(): # 条件1 # 内部函数 print(x) # 条件2 # 外部环境的一个变量 return inner # 结论 # 函数名字可以作为返回值(高阶函数) # 内部函数inner就是一个闭包 # inner() # 局部变量,全局无法调用 f = outer() f() # 执行结果 10 # 当outer函数被调用执行完了之后,在用f调用inner函数理论是打印不出x这个局部变量的,这就闭包的作用 # 闭包的定义:如果在一个内部函数里,对在外部的作用域(但不是在全局的作用域)的变量进行引用,那么内部函数就被认为是闭包(closure)
假如:有一个需求,两个功能函数,在不修改源代码的及源代码的调用方式下,实现计算两个功能的运行时间差
实例
import time # 这个新加的函数先加载到内存 def show_time(f): # 新加运行时间差的功能函数 """装饰器函数,这个函数本身就是一个装饰器""" def inner(): # 由此,这里产生一个闭包现象函数,内部调用外部定义时的函数参数 start_time = time.time() f() end_time = time.time() print("spend %s" %(end_time - start_time)) return inner def foo(): # 源代码功能函数 print("foo.....") time.sleep(2) def bar(): # 服务功能函数 print("bar.....") time.sleep(3) foo = show_time(foo) foo() # bar = show_time(bar) # bar()
装饰器的高级写法
import time # 这个函数先加载到内存 def show_time(f): # 新加运行时间差的功能函数 """装饰器函数,这个函数本身就是一个装饰器""" def inner(): # 由此,这里产生一个闭包现象函数,内部调用定义时的函数参数 start_time = time.time() f() end_time = time.time() print("spend %s" %(end_time - start_time)) return inner @show_time # foo = show_time(foo) def foo(): # 源代码功能函数 print("foo.....") time.sleep(2) @show_time def bar(): # 服务功能函数 print("bar.....") time.sleep(3) # foo() bar() # 执行结果 bar..... spend 3.000763416290283

带参数的装饰器函数
import time def show_time(add): # add函数名字作为变量传给这个函数 def inner(a, b): # 定义运行时间函数,定义add功能函数的形参 start_time = time.time() # 开始时间 add(a, b) # 调用add函数 end_time = time.time() # 结束时间 print("spend %s" %(end_time - start_time)) # 打印计算的运行时间 return inner @show_time # 装饰器 def add(a, b): # 加法器功能函数 print(a + b) time.sleep(1) add(1,2) # 执行结果 3 spend 1.0003678798675537 [Finished in 1.1s]
优化装饰器函数,使用不定长参数,实现加法器的叠加效果
装饰器函数调用功能函数加参数的实例
import time def show_time(add): # add函数名字作为变量传给这个函数 def inner(*a, **b): # 定义运行时间函数,定义add功能函数的形参 start_time = time.time() # 开始时间 add(*a, **b) # 调用add函数 end_time = time.time() # 结束时间 print("spend %s" %(end_time - start_time)) # 打印计算的运行时间 return inner @show_time # 装饰器 def add(*a, **b): # 实现一串数字相加的和功能函数, b是字典的不定长参数,这里没有用到 sums = 0 for i in a: sums += i print(sums) time.sleep(1) add(1,2,3,4) # 执行结果 10 spend 1.00032639503479 [Finished in 1.1s]
装饰器加参数
需求:假如两个功能函数,想让其中任意功能函数在计算运行时间之外打印日志,一个需要打印logger日志,一个不需要打印logger日志,就可以用装饰器函数加参数的形式了
import time def logger(flag=""): # 加这一层嵌套的原因是传一个日志参数,让装饰器去调。这里加一个空的默认参数,功能函数不调用日志记录就可以传一个空值就好了 def show_time(add): # add函数名字作为变量传给这个函数 def inner(*a, **b): # 定义运行时间函数,定义add功能函数的形参 start_time = time.time() # 开始时间 add(*a, **b) # 调用add函数 end_time = time.time() # 结束时间 print("spend %s" %(end_time - start_time)) # 打印计算的运行时间 if flag == "true": # 判断功能功能函数是否需要打印日志 print("日志记录") return inner # 返回给show_time return show_time # 返回给logger @logger("true") # 装饰器。 # logger()相当于@show_time def add(*a, **b): # 实现一串数字相加的和功能函数, b是字典的不定长参数,这里没有用到 sums = 0 for i in a: sums += i print(sums) time.sleep(1) @logger() def bar(*a, **b): # 服务功能函数 sums = 0 for i in a: sums += i print(sums) time.sleep(3) add(1,2,3,4) # bar(1,2,3) # 运行结果 10 spend 1.0003623962402344 日志记录 [Finished in 1.1s]

浙公网安备 33010602011771号