Python-Day 5-装饰器
一、定义
1、装饰器:本质是函数。
2、功能:用来装饰其他函数,顾名思义就是,为其他的函数添加附件功能的。
3、原则:不能修改被装饰函数的源代码、不能修改被装饰函数的调用方式
4、函数即"变量", 高阶函数+嵌套函数 => 装饰器
def test():
print("LOVE")
#正确写法,没有修改源码
def test1():
print("LOVE ME")
#错误写法,不能修改源码
def test1():
print("LOVE ME")
test()
#调用
test1()
二、函数即变量
1、python的内存机制
在python解释器中,有一个概念叫做引用基数,例如,x=1这个b变量,先在内存当中把1这个值存放下来,这个x其实就是1的门牌号,x=1就是对1的一次引用。
python等到1所对应的门牌号都没有了,就会把1给清掉,这个也是python的内存回收机制。
python用del去清理门牌号,就是对1的值引用的变量,del x就表示清理掉1对应的x的门牌号。如果x没有被del,则x永远不会被删除,除非程序结束了。del删除的不是1,只是把门牌号x删除了,定期刷新时,发现1没有被其他门牌号引用了,1才会被清掉。
#变量
x = 1
#函数
def test():
pass

2、函数在内存的表现形式
①test函数在fex函数之后定义
def test():
print("in test")
fex()
def fex():
print("in fex")
test()
#结果
in test
in fex
②test函数在fex函数之前定义
def fex():
print("in fex")
def test():
print("in test")
fex()
test()
#结果
in test
in fex
上面两种写法,输出结果是一样的
③test函数在fex函数之后声明
def test():
print("in test")
fex()
test()
def fex():
print("in fex")
#结果 Traceback (most recent call last): File "/Users/bianbian/PycharmProjects/test/test10.py", line 5, in <module> test() NameError: name 'test' is not defined
因为在执行test函数时,当调用fex函数时,fex还函数还定义,所以报错。
三、高阶函数
实现高阶函数的条件:把一个函数名当做实参传给另外一个函数,且返回值中包含函数名
1、把一个函数名当做实参传给另外一个函数
import time
def fex():
time.sleep(3)
print("in the fex")
def test(func):
print(func)
start_time = time.time()
func()
stop_time = time.time()
print("the func run the is %s" % (stop_time - start_time))
#没有修改fex的代码
test(fex) #把fex函数名当做实参传到test中
#结果
<function fex at 0x10df3b268>
in the fex
the func run the is 3.0029611587524414
作用:在不修改被装饰函数源代码的情况下为其添加功能
2、返回值中包括函数名
import time
def fex():
time.sleep(3)
print("in the fex")
def test1(func):
print(func)
return(func) #返回函数的内存地址
test=test1(fex)
fex()
#没有改变fex函数的调用方式
#结果
<function fex at 0x1090ab268>
in the fex
作用:不修改函数调用方式
四、嵌套函数
在一个函数的函数体内,用def 去声明一个函数,而不是去调用其他函数,称为嵌套函数。
def fex():
print("in fex")
def fun():
#在fex函数体内声明一个函数fun
print("in fun")
fun()
fex()
变量的作用域:从里往外找,一层一层的的找。
x=0
def test():
x=1
def test1():
x=2
def test2():
x=3
print(x)
test2()
test1()
test()
#结果
3
五、装饰器
装饰器实现的条件:高阶函数+嵌套函数 =>装饰器
import time
#定义内置函数
def timmer(func): #timmer(test) func=test
def fex():
start_time=time.time()
func() #run test()
stop_time=time.time()
print("the func run time is %s" %(start_time-stop_time))
return fex
#装饰test函数
@timmer # 相当于test = timmer(test)
def test():
time.sleep(3)
print("in the test")
#直接执行test函数
test()
#结果
in the test
the func run time is -3.0014219284057617
执行步骤:
- 执行timmer函数,timmer(test) 返回值赋值给test变量,即test=timmer(test)
- 此时的test的值是执行timmer函数返回值fex,即test=fex
- 所以执行test,其实就是执行的是fex函数,test()其实就是执行fex函数。
1、执行函数带参数
import time
#定义内置函数
def timmer(func): #timmer(test) func=test
def fex():
start_time=time.time()
func() #run test()
stop_time=time.time()
print("the func run time is %s" %(start_time-stop_time))
return fex
#装饰test1函数
@timmer # 相当于test1 = timmer(test1)
def test1(age,name):
print("name:%s,age:%s"%(age,name))
#直接执行test函数
test1()
#结果
Traceback (most recent call last):
File "/Users/bianbian/PycharmProjects/test/test11.py", line 16, in <module>
test1()
File "/Users/bianbian/PycharmProjects/test/test11.py", line 6, in fex
func() #run test()
TypeError: test1() missing 2 required positional arguments: 'age' and 'name'
因为这边执行的test1函数其实就是执行的fex函数,fex函数体内的func()其实就是执行test1函数,但是,test1需要传入name和age两个参数,所以报错。那怎么解决呢?传入参数!
但是你又不能确定传入几个参数,所以用非固定参数传参
import time
#定义内置函数
def timmer(func): #timmer(test) func=test
def fex(*args,**kwargs):#传入非固定参数
start_time=time.time()
func(*args,**kwargs) #传入非固定参数
stop_time=time.time()
print("the func run time is %s" %(start_time-stop_time))
return fex
#不带参数
@timmer
def test1(): # 相当于test1 = timmer(test1)
time.sleep(3)
print("in the test1")
#带参数
@timmer # test2 = timmer(test2)
def test2(age,name):
print("name:%s,age:%s"%(age,name))
#调用
test1()
test2("bianbian",18)
#结果
#test1
in the test1
the func run time is -3.0028131008148193
#test2
name:bianbian,age:18
the func run time is -1.5020370483398438e-05
2、执行函数有返回值
如果,被调函数的有返回值??
def timmer(func): #timmer(test) func=test
def fex(*args,**kwargs):#传入非固定参数
res=func(*args,**kwargs) #传入非固定参数
return res
return fex
#不带参数
@timmer
def test1(): # 相当于test1 = timmer(test1)
print("in the test1")
return "from the test1" # 执行函数test1有返回值
res = test1()
print(res)
#结果
in the test1
from the test1
通过上面的例子,可以看出,就是在内置函数中把传入参数的执行结果赋给res,然后再返回res变量。
3、带参数的装饰器
之前装饰器都是没有带参数的,但是访问不到页面时,你用的验证的方式来源不同,这时你该怎么办?
name,password="bianbian","bfj123321"
def auth(auth_type):#传递装饰器的参数
print("auth_type",auth_type)
def outer_wrapper(func):# 将被装饰的函数作为参数传递进来
def wrapper(*args,**kwargs):# 将被装饰的函数作为参数传递进来
print("wrapper func args",*args,**kwargs)
username=input("Username:").strip()
password=input("Password:").strip()
if auth_type == "local":
if name == username and password == password:
print("%s has passed authentication"%name)
res=func(*args,**kwargs)
print("--------after authentication")
return res
else:
exit("Invalid username or password")
elif auth_type == "ldap":
pass
return wrapper
return outer_wrapper
def index():
print("Welcome to index")
@auth(auth_type="local") #带参数装饰器
def home():
print("Welcome to home page")
return "from home"
@auth(auth_type="ldap") #带参数装饰器
def bbs():
print("Welcome to bbs page")
index()
home()
bbs()
结果:

可以看出,执行步骤:
- outer_wrapper = auth(auth_type="local")
- home = outer_wrapper(home)
- home()
所以这个函数的作用分别是:
- auth(auth_type) 传递装饰器的参数
- outer_wrapper(func) 把函数当做实参传递进来
- wrapper(*args,**kwargs) 真正执行装饰的函数

浙公网安备 33010602011771号