初识函数装饰器
先了解作用域、高阶函数、闭包的概念
作用域
全局变量(模块内定义)、局部变量(函数内定义)、嵌套作用域(内部函数的作用域)、内置作用域(python内置定义)
a=1 #全局变量,定义在模块中
def foo():
b=2 #局部变量,定义在函数里
print("a1:",a)
print("b1:",b)
def inner():
c=3 #嵌套作用域
print("b3:", b)
print("c3:", c)
print("b4:", b)
# print("c4:", c)#无法读取局部变量
print("a2:",a)
# print("b2:", b)#无法读取局部变量
foo()
print(__name__) #内置作用域,python内置定义
a2: 1
a1: 1
b1: 2
b4: 2
__main__
高阶函数
函数名可以赋值给其他对象、函数名可以作为返回值、函数名可以作为参数传递
#================1、函数名可以赋值给其他对象================
def foo():
print("执行foo函数")
#方法一
a=foo()
#方法二
a=foo #函数名可以赋值给其他对象
a()
#结果
执行foo函数
执行foo函数
#================2、函数名可以作为返回值================
def foo():
print("执行foo函数")
def inner():
print("执行inner函数")
return inner #函数名就是变量,就可以作为返回值
print("----执行a=foo()------")
a=foo() #返回变量inner,执行foo函数
print("----执行a()------")
a() #相当于inner(),执行inner函数
#结果
----执行a=foo()------
ִ执行foo函数
----执行a()------
ִ执行inner函数
#================3、函数名可以作为参数传递================
def foo(func):
func()
def bar():
print("执行bar函数")
foo(bar)
#结果
执行bar函数
闭包
在内部函数里调用外部作用域的变量(但是非全局变量)
x="全局变量,定义在模块中"
def outer():
y="局部变量,定义在函数里"
def inner():
print(y)
return inner
#调用inner函数
outer()() #方法一
a=outer() #方法二
a()
"""上述方法即为闭包,在内部函数里调用外部作用域的变量(但是非全局变量)"""
#结果
局部变量,定义在函数里
局部变量,定义在函数里
装饰器
允许扩展已有功能代码,禁止修改已有功能代码;比如:被装饰函数A(),装饰函数B(A),在被装饰函数A()上@装饰函数B,相当于A=B(A),调用时只需要A(),已达到上述目的扩展已有功能而不修改已有功能的代码
方法一:写一个装饰函数扩展功能,原方法作为装饰函数的参数
import time
def foo():
print("调用很多接口")
time.sleep(3)
def show_time(func):
beginTime=time.time()
func()
endTime = time.time()
print("总耗时:",endTime - beginTime)
show_time(foo)
"""
上述方法缺点:加了show_time后,原先调用foo函数的地方都要重新修改为调用show_time,且foo作为传参
"""
#结果
调用很多接口
总耗时:3.002992630004883
方法二:装饰函数返回函数,并用装饰器简化调用
import time
def show_time(func): #装饰函数
def inner():
beginTime=time.time()
func()
endTime = time.time()
print("总耗时:",endTime - beginTime)
return inner
@show_time # 等同于foo=show_time(foo) #foo=inner
def foo(): #被装饰函数
print("调用很多接口")
time.sleep(1)
#----调用方法一:不加装饰器----------
foo=show_time(foo) #foo=inner
foo()
#----调用方法二:被装饰函数上@装饰函数----------
foo()
"""
上述为一个简单的装饰器
"""
#结果
调用很多接口
总耗时:1.0051441192626953
带参数的函数装饰器
import time
def show_time(func):
def inner(case_name):
beginTime=time.time()
func(case_name)
endTime = time.time()
print("总耗时:",endTime - beginTime)
return inner
@show_time
def foo(case_name): #foo函数带参数,则inner和里面的func都要带参数
print("调用很多接口")
time.sleep(1)
foo('参数')
"""
foo函数带参数,则inner和里面的func都要带参数
调用foo函数也要带参数
"""
#结果
调用很多接口
总耗时:1.0126347541809082
带参数的函数装饰器-不定长参数
import time
def show_time(func):
def inner(*args,**kwargs): #不定长参数
beginTime=time.time()
func(*args,**kwargs)
endTime = time.time()
print("总耗时:",endTime - beginTime)
return inner
@show_time
def foo1(a,b):
print("foo1调用很多接口")
time.sleep(1)
@show_time
def foo2(a,b,c,d):
print("foo2调用很多接口")
time.sleep(1)
foo1('参数a','参数b')
foo2('参数a','参数b','参数c','参数d')
#结果
foo1调用很多接口
总耗时:1.001772403717041
foo2调用很多接口
总耗时:1.0102813243865967
多个装饰器执行顺序
def dec1(func):
print("1111")
def one():
print("2222")
func()
print("3333")
return one
def dec2(func):
print("aaaa")
def two():
print("bbbb")
func()
print("cccc")
return two
@dec1
@dec2
def foo():
print("调用很多接口")
foo()
"""
多个装饰器执行顺序是从最后一个装饰器开始,执行到第一个装饰器,再执行函数本身
"""
#结果
aaaa
1111
2222
bbbb
调用很多接口
cccc
3333
初识类装饰器
类装饰器本质上和函数装饰器原理、作用相同,都是为其它函数增加额外的功能。使用类装饰器可以直接依靠类内部的__call__方法来实现,当使用 @ 形式将类装饰器附加到函数上时,就会调用类装饰器的__call__方法。而不需要向函数装饰器那样,在装饰器函数中定义嵌套函数,来实现装饰功能。
__call__方法
class A:
pass
a=A()
a()
#结果
TypeError: 'A' object is not callable 无法调用
class A:
def __init__(self):
self.name="AAA"
def __call__(self):# 类中实现了__call__方法
print("类中实现了__call__方法:"+self.name)
a=A()
a()
"""
类对象可调用,并在调用类对象的时候,自动执行__call__方法
"""
#结果
类中实现了__call__方法:AAA
类装饰器实例
import time
class show_time():
def __init__(self, func): # 初始化函数中传入函数对象的参数
self._func = func
def __call__(self): # 定义__call__方法,直接实现装饰功能
beginTime = time.time()
self._func()
endTime = time.time()
print('总耗时:', (endTime - beginTime))
@show_time # Foo=show_time(Foo)
def Foo():
print('调用很多接口')
time.sleep(1)
Foo()# Foo=show_time(Foo)(),没有嵌套关系了,直接执行Foo的 __call__方法,实现装饰功能
#结果
调用很多接口
总耗时:1.0099809169769287