摘要: 本文从学习装饰器需要用到的基础知识入手, 用简单代码附以实例验证,在彻底理解基础知识的情况下帮助逐步理解, 装饰器的原型
要点: 从闭包及函数名可当参数传递作为基础理解思路, 由浅入深引入Python装饰器原型, 进而引出装饰器
**装饰器背景:** 在不改变原函数代码, 且保持原函数调用方法不变的情况下, 给原函数增加新的功能 (或者给类增加新属性和方法)
**核心思想: ** 用一个函数(或者类) 去装修 一个旧函数 (或者类) , 造出一个新函数(或者新类)
Python万物皆对象, 可以随意赋值使用
def func():
print("第三: ","我是一个函数的输出结果")
a = 1
print("第一: 我是一个变量 ",a)
a = func #将函数名赋值给变量
print("第二: 我是一个函数名 ",a)
a()
>>>第一: 我是一个变量 1
>>>第二: 我是一个函数名 <function func at 0x000000000220AAE8>
>>>第三: 我是一个函数的输出结果
变量作用域
# 根据 LEGB原则, 内函数使用外函数的局部变量
def outer():
a = 0
print("我是外部函数的 a:",a)
def inner():
print("我是内部函数打印的 a:",a)
> > > 我是外部函数的 a: 0
> > > 我是内部函数打印的 a: 0
# 引入 nonlocal, 内函数可以修改外函数
def outer():
a = 0
print("我是外部函数的 a:",a)
def inner():
nonlocal a
a += 1
print("我是内部函数加工过的 a:",a)
>>>我是外部函数的 a: 0
>>>我是内部函数加工过的 a: 1
闭包( 延长局部变量生存时间 )
# 内函数 夹带 外函数的局部变量
def outer():
a = 0
print("我是外部函数打印的 a:",a)
def inner():
print("我是内部函数打印的 a:",a)
return inner
res = outer() # res接收的是一个函数名
print("我是返回出来的内函数名: "res)
res()
>>>我是外部函数打印的 a: 0
>>>我是返回出来的内函数名: <function func at 0x000000000220AAE8>
>>>我是内部函数打印的 a: 0
>>>
# 内函数 夹带 修改后的外函数的局部变量
def outer():
a = 0
print("我是外部函数打印的 a:",a)
def inner():
nonlocal a
a += 1
print("我是内部函数修改过的 a:",a)
return inner
res = outer() # res接收的是一个函数名
print("我是返回出来的内函数名: "res)
res()
>>>我是外部函数打印的 a: 0
>>>我是返回出来的内函数名: <function func at 0x000000000220CA97>
>>>我是内部函数修改过的 a: 1
函数名可以当做参数传递
#新函数对旧函数修饰
def old():
print('我是 旧函数')
def new(f):
print('我是 新函数, 我可以输出 旧函数')
f()
new( old ) #把旧函数名当做参数, 传递给新函数, 在新函数内产生变化
>>>我是 新函数, 我可以输出 旧函数
>>>我是 旧函数
装饰器原型
# ### 利用闭包,将函数名当参数传递
def outer(f):
def inner():
print("我是外部传进来的old :",f)
f()
print("我是修饰工,我在旧函数后显示")
return inner
def old():
print("我是旧函数")
print("我是最初的old: ",old)
print("我是返回出来的内函数inner: ",outer(old)) #outer把函数名old当参数传回函数内部进行加工, 把函数名inner返回
old = outer(old) #实际上, 旧函数名old已被重新赋值为inner
print("我不是原来的old了 ",old)
old() #经过改造, 虽然调用结果不变, 但是运行结果已变化
>>>我是最初的old: <function old at 0x00000000021CAA60>
>>>我是返回出来内函数inner: <functionouter<locals>.inner at 0x00000000021CAAE8>
>>>我不是原来的old了 <function outer.<locals>.inner at 0x00000000021CAAE8>
>>>我是外部传进来的old : <function old at 0x00000000021CAA60>
>>>我是旧函数
>>>我是修饰工,我在旧函数后显示
装饰器
# ### 用 @outer 修饰
def outer(f):
def inner():
print("我是外部传进来的old :",f)
f()
print("我是修饰工,我在旧函数后显示")
return inner
@outer #实际上,将 old = outer(old) 这句改成 @outer, 放在old函数上方
def old():
print("我是旧函数")
old()
>>>我是外部传进来的old : <function old at 0x00000000021CAA60>
>>>我是旧函数
>>>我是修饰工,我在旧函数后显示
装饰器的嵌套: 下层装饰器修饰后的函数, 再次被上层装饰器修饰
def kuozhan(f):
def inner():
print("1我是扩展函数,接收外部传进来的新old :",f)
f()
print("4我是扩展函数,我在新old函数后显示")
return inner
def outer(f):
def inner():
print("2我是outer函数,接收外部传进来的old :",f)
f()
print("3我是outer函数,我在old函数后显示")
return inner
@kuozhan #old = kuozhan(outer(old))
@outer #old = outer(old)
def old():
print("我是old函数")
old()
>>>1 我是扩展函数,接收外部传进来的新old : <function outer.<locals>.inner at 0x000000000250AB70>
>>>2 我是外部传进来的old : <function old at 0x000000000250AAE8>
>>> 我是old函数
>>>3 我是修饰工,我在旧函数后显示
>>>4 我是扩展函数,我在新old函数后显示