装饰器其实在版本迭代和代码重用上,有很明显的作用,但是他的语法形式,其实有一定的独特性,所以很多小伙伴对他只是一知半解。
其实并没有这么的复杂,这里我就给大家拆开了,一步一步的来研究下装饰器到底是怎么玩的。
废话不多说,开搞
def func_1(f):
"""
这是一个有内部函数的函数
:param f: 参数f是一个可执行的函数
:return: 返回内部函数的地址
"""
def inner():
"""
这是一个内部函数,执行f()并返回f()的执行结果,f在上面
:return: 返回值为函数f的执行结果
"""
print('this is func1')
return f()
return inner
没问题,我们测试一下
# 这是一个简单的函数
def func_2():
print('func_2')
# 获得内部函数
test_func = func_1(func_2) # test_func == inner
test_func() # == inner()
# this is func1
# func_2
结果ok,如果有小伙伴不明白为什么,请一定好好的找一个python教程看一下
好了接下来,我要给我们的测试添加条件
1、不允许修改func_2代码,把func_2这个函数封版,按照开放封闭原则
2、我要以func_2( ) 的形式得到上面输出的结果
好!我们一步一步来
第一步:我先来做个壳,起个名字叫做clothes,(就像穿了件衣服)
def clothes(func):
def inner():
return func()
return inner
简单不
tips:如果这个还看不懂,请认真复习基础知识,因为这是一个对于任何编程语言,基础架构的理解
第二步:我给这个壳加工一下,以防需要被加壳的函数有参数
def clothes(func):
def inner(*args, **kwargs):
return func(*args, **kwargs)
return inner
这里有一个知识点,(这个知识点我知识测试过,并没有查过文档,但是个人感觉应该没错,错了大佬请拍砖)
*args 如果作为参数传递,他会根据函数声明的个数进行分解
怎么理解?
1、*args是不定参数 他是一个tuple
2、*args不能作为变量来声明,他是函数参数的一个特定参数
如果函数声明是func(a,b,c,d),如果我传给他一个不定参数 *args=(1,2,3,4) 那就会自动去契合,他就会让a=1,b=2,c=3,d=4
注意:
首先,如果你想用*args去给另一个函数传参数,请匹配那个函数的参数个数
第二点,由于不能用*args去声明变量,那*args只能在函数内部传递,那就说明,你只能给内部函数传递*args
这里先这样,大家可以自己尝试下
继续
第三步:让壳去做点自己想做的事情
def clothes(func):
def inner(*args, **kwargs):
print('I am a cloth')
return func(*args, **kwargs)
return inner
第四步:我们给函数套壳
def func_2(str1):
print(str1)
func_2 = clothes(func_2)
func_2('111')
# I am a cloth
# 111
这时候,func_2已经被套壳了,func_2 == inner
套壳完成!
第一次看可能有点绕,我给大家往白了说,func_2 就是用来获取clothes函数的返回值,那如果返回是个int呢?
def clothes(func):
def inner(*args, **kwargs):
print('I am a cloth')
return func(*args, **kwargs)
return 1 # int
func_2 = clothes(func_2)
print(func_2)
# 1
这么一看是不是就看明白了
这就是装饰器的原理,并且装饰器给了我们一个更方便的语法
def clothes(func):
def inner(*args, **kwargs):
print('I am a cloth')
return func(*args, **kwargs)
return inner
@clothes
def func_2(a):
print(a)
func_2(111)
@clothes就是装饰器,把他按在一个函数之上,就代表要用下方函数地址作为参数,传递给装饰器函数,然后返回再返回给被装饰的函数(也就是func_2)
这时候你再调用func_2函数就会达到,不修改函数内部,也不修改函数调用方法,就能修改函数功能的作用
基本功能做完,我们再加深一下,能不能给inner函数传个参数
上面我是打印了一句话 print(‘I am a cloth’) 这次我想打印 print(data) data是个变量
我先给代码,大家先结合上面的原理看一看
def out(data):
def clothes(func):
def inner(*args, **kwargs):
print(data)
return func(*args, **kwargs)
return inner
return clothes
@out("abcd")
def func_2(a):
print(a)
我给个过程提示:@out(“abcd”)得拆开
@+out(“abcd”)
1、tmp_func = out(“abcd”)
2、@tmp_func
理解了吧
@看做一个运算符,右边如果还是一个需要进行运算的结果,类似 int(str(‘a’))
好了,就这样吧,其实装饰器之前我有所了解,但是原理上还是有点问题,所以拖了好久。如果有还有问题,欢迎讨论