装饰器
定义:本职是函数,(装饰其他函数)就是为其他函数添加附加功能。
原则:
1.不能修改被装饰的函数的源代码
2.不能修改被装饰函数的调用的方式
先来一个直观感受
import time
def timmer(func): ##
def warpper(*args,**kwargs):
start_time=time.time()
func() ##run test1()
stop_time=time.time()
print("the func time is %s"%(start_time-stop_time))
return warpper
@timmer #@加函数名,即可调用函数
def test1(): ###源代码
time.sleep(3)
print("in the test1")
test1()
实现装饰器的知识储备:
1.函数即"变量"
2.高阶函数
3.嵌套函数(函数里面def声明一个函数叫嵌套函数,调用函数不叫嵌套)
下面进行一波实验:如下三种结果(验证1.函数即“变量”)
A.输出报错没有bar函数
def foo():
print("in the foo")
bar()
foo()
B.成功
def bar():
print("in the bar")
def foo():
print("in the foo")
bar()
foo()
C.输出报错,没找到定义的bar函数
def foo():
print("in the foo")
bar()
foo()
def bar():
print("in the bar")
在将函数即“变量”的时候,先讲下python内存存储变量的机制。
当设定一个变量x=1时,内存看成一个大house,这时候大house会腾出一个房间将变量值1放入这个房间,并贴上x的门牌号。
如果是x=1,y=x,那就是变量值1这个房间将会有两个门牌号,即x&y。如图所示:
而在python内存的回收机制中,当你的房间没有门牌号时,它就会默认回收。这样可以节约空间。而当两个或多个变量值都一样时,它不会给你创建N个房间,而是同一个房间内贴上N个门牌号。
凡是也有例外,有人就会说了,那就不会有没有变量名的变量了吗?这个在python中,还真有即匿名函数lambda。当lambda x:x*3,结果是占用的内存地址。
这里的
print(“in the poo”)
bar()
就是函数体相当于变量存放在内存中。poo()就是门牌号,当执行A时之所以会报错,就是因为没有找到bar的函数体。而C虽然定义了bar()但是定义的位置不对,函数都是从上往下读取,当执行poo()之前并没有定义,所以会报错找不到bar
2.高阶函数(又分以下两种)
a:把一个函数名当做实参传递给另外一个函数
import time
def bar():
time.sleep(3)
print("in the bar")
def test1(func): ##根据test1(bar)的调用可以看出,这里的func = bar。这就是把bar函数名传递给func当test1的实参
start_time=time.time()
func() #run bar()
stop_time=time.time()
print("the func run time is %s"%(stop_time-start_time))
test1(bar)
b:返回值中包含函数名
import time
def bar():
time.sleep(3)
print("in the bar")
def test2(func):
print(func)
return func #f返回bar的内存值
print(test2(bar))
t=test2(bar) #test2执行结果赋值给了t,相当于把bar(赋值给了t,当使用t()时,就是在执行bar函数
t() #run bar()
3.嵌套函数 (在一个函数体内用def声明一个函数叫嵌套。调用不叫嵌套)
#局部即变量
def foo():
def bar():
print("in the bar")
bar() ##想要输出print结果就需要一层层的调用
foo()
#局部作用和全局作用域的访问顺序
x=0
def boo():
def daa():
x=2
def son():
x=3
print(x)
son()
daa()
boo()
猜测下这里的输出结果是:
下面写个简单的装饰器。(高阶函数+嵌套函数=》装饰器)
不设定函数实参
import time
def timer(func): ##func=test1=test2
def deco():
start_time=time.time()
func() ##func=test1 =test2
stop_time=time.time()
print("the funce run time is %s" %(stop_time-start_time))
return deco
def test1():
time.sleep(3)
print("in the test1")
@timer
def test2():
time.sleep(3)
print("in the test2")
test1=timer(test1)
test1() ##-->deco
test2()
当设定test实参时,可以这样写。deco() func()里面都直接*args,***kwargs不限量。如果具体某一个参数,那就可以修改为具体的。
import time
def timer(func):
def deco(*args,**kwargs):
start_time=time.time()
func(*args,**kwargs)
stop_time=time.time()
print("the funce run time is %s" %(stop_time-start_time))
return deco
def test1():
time.sleep(3)
print("in the test1")
@timer #非固定参数name
def test2(name):
time.sleep(3)
print("in the test2",name)
test1=timer(test1)
test1() ##-->deco
test2("alex")
模拟远端登录与本地登录试验:
user,passwd="alex","abc"
def auth(auth_type):
print("auth>>>",auth_type)
def outer_wrapper(func):
def wrapper(*args,**kwargs):
print("*args,**kwargs",*args,**kwargs)
if auth_type=="local":
username=input("Input user: ").strip()
password=input("Input password: ").strip()
if username==user and password==passwd:
print("\033[32;1mUser has passed authentication\033[0m")
res=func(*args,**kwargs)
return res
else:
exit("\033[31;1mIminvalid username or password\033[0m")
elif auth_type=="ldap":
print("不会")
return wrapper
return outer_wrapper
def index():
print("welcome to index page")
@auth(auth_type="local") ##本地验证登录
def home():
print("welcome to home page")
return "from home"
@auth(auth_type="ldap") ##远端验证登录
def dds():
print("welcome to dds page")
index()
print(home())
dds()