【Python实践】_装饰器
真正的稳定,是自己不断成长,不断寻找新的空间。与其要稳定,不如开始拥抱这个变化的时代,让自己准备好。
python实践
【写在前面】:
曾经在面试的时候问过很多人“什么是装饰器?”,但是都没有得到一个很简洁明了的答案,希望这篇文章能使你对装饰器有个比较清楚、简洁的认识。
【材料】:
参考材料 《Python进阶》
【Step1】:什么是装饰器?
从字面意思来理解,装饰+器,装饰我们都知道,是在原有基础上增加某些功能,达到一定的效果,python中的装饰器也是在原来函数(类)上增加一些特殊的功能,但是并不是直接去修改原来的函数(类),而是新写一个函数,这个函数的功能就是在对原函数(类)二次处理(并非重构)
简单举例如下:
# -*- coding: utf-8 -*-
def greet(fun):
def pre():
print("I'm pre")
t = fun()
return t
return pre
@greet
def test():
return "I'm test"
if __name__ == '__main__':
print(test())
运行结果如下:
I'm pre
I'm test
上面的greet函数就是一个装饰器,其作用就是对test函数做装饰,在待装饰的函数前面使用@符号来调用装饰函数。
【Step2】:对Step1的解释
1、对函数的认识,通常def test()被叫做定义一个test函数,这其中test是函数名,当使用test()时表示在调用该函数,可以拿到return值,当使用test时并不会调用,只是将函数作为一个变量,可以赋值给其他变量,比如a,这样a变量就有了test函数的功能,而且两个函数名都指向该函数的内存地址(0x012B5618)。这里我们了解到原来函数不是只能直接被调用,函数名还能够作为参数使用,这一点很重要。
def test():
return "I'm test"
if __name__ == '__main__':
print(test())
print(test)
a = test
print(a)
print(a())
del test
print(a())
运行结果如下:
I'm test
<function test at 0x00B25618>
<function test at 0x00B25618>
I'm test
I'm test
2、函数中定义函数
函数out中包含子函数inner,调用out函数时,会return出该函数的输出,即“here is out...”,在out函数内部有print(inner())来打印inner函数的return结果,即“here is inner...”(如果没有这一句,是不会调用inner函数的),而由于inner函数是在out函数内部的,所以不能被单独调用。
举例如下:
def out():
print("here is out...")
def inner():
return "here is inner..."
print(inner())
out()
inner()
运行结果如下:
here is out...
here is inner...
File "D:/auto_case/DailyWork/test.py", line 10, in <module>
inner()
NameError: name 'inner' is not defined
3、从函数中返回函数
现实中很少会在函数中去执行一个函数,更多的时候是希望将内部函数作为外层函数的return值,所以我们可以这样改造,达到返回内层函数的效果
(1).out函数,这个就是out的一个函数,return a
(2).out1函数,内层inner1函数,在out1函数中使用inner1()调用inner1,返回inner1函数return的值;
(3).out2函数,内层inner2函数,在out2函数中使用inner2将函数赋值给了变量c,返回函数c(注意不是函数c被调用的值);
(4).out3函数是对out2函数的简写,功能一样;
(5).在print中,重点是out3()是一个函数,所以要得到函数返回值,就需要在其后面加上小括号,达到调用函数的效果,即out3()()。
举例如下:
# -*- coding: utf-8 -*-
def out():
a = "test"
return a
def out1():
def inner1():
return "here is inner..."
b = inner1()
return b
def out2():
def inner2():
return "here is inner2..."
c = inner2
return c
def out3():
def inner3():
return "here is inner3..."
return inner3
print(out())
print(out1())
print(out2())
d = out2()
print(d())
print(out3())
print(out3()())
运行结果如下:
test
here is inner...
<function out2.<locals>.inner2 at 0x01A3D8E8>
here is inner2...
<function out3.<locals>.inner3 at 0x01A3D618>
here is inner3...
4、将函数名作为参数传递给其他函数
函数名可以代表函数,也可以赋值,所以能够作为参数专递到函数中去,在函数中只要在参数后面加上小括号,就拥有了该函数的功能。我在下面的函数中加了步骤输出,读者可以比较清楚的知道函数是如何调用的。
举例如下:
# -*- coding: utf-8 -*-
def test():
print("step 4")
return "I'm test"
def greet(fun):
print("step 1")
def pre():
print("step 2")
print("I'm pre")
t = fun()
return t
print("step 3")
return pre
print(greet(test))
print(greet(test)())
运行结果如下:
C:\Users\54788\AppData\Local\Programs\Python\Python35-32\python3.exe D:/auto_case/DailyWork/test.py
step 1
step 3
<function greet.<locals>.pre at 0x01C0D588>
~~~~~~虚拟分割线~~~~~~~
step 1
step 3
step 2
I'm pre
step 4
I'm test
Process finished with exit code 0
5、装饰器标识符“@”,使用@装饰器名在待装饰函数前,即可完成不修改待装饰函数的情况下,修改函数的功能,注意装饰器必须在被装饰函数前定义。
【Step3】:应用场景举例
鉴权在打开页面和登录中的使用
# -*- coding: utf-8 -*-
def auth(fun):
def base_auth(*param):
if param[0] == '123%$&*sdhjd':
return fun(*param)
else:
return no_auth()
return base_auth
def no_auth():
return "you have no auth"
@auth
def open_page(param):
return "begin to open page..." + str(param)
@auth
def login(param1,param2):
return "begin to login..." + str(param2)
print(open_page('123%$&*sdhjd'))
print(open_page('123%$&*'))
print(login('123%$&*sdhjd', 'test'))
print(login('123%$&*', 'test'))