闭包的概念
- 定义在函数内部的函数,对外部作用域的变量进行应用。
作用
- 闭包执行完后,任然能够保持当前的运行环境(闭包中不可以修改外部函数的局部变量)
- 闭包可以根据外部作用域的局部变量来得到不同的结果
举个例子
def func1(x): #代码1
def inner(y): #代码2
print("执行inner函数") #代码3
return x*y #代码4
print("执行fun1函数") #代码5
return inner #代码6
s=func1(3)(2) #s=6 #代码7
--------执行结果-----------
执行fun1函数
执行inner函数
执行过程分析
- func1(3)(2)先调用func1(3),执行到代码2,发现是函数,跳过不执行
- 继续执行代码5,继续执行代码6返回一个inner函数
- 然后调用inner(2),依次执行代码3、代码4
函数执行特点
自上而下执行、函数只有被调用时才会执行
装饰器
- 不改变代码结构的情况下给代码添加新的功能
- 将被装饰的函数当做参数传递给装饰器函数,并返回装饰后被装饰的函数
- 装饰器可以是函数也可以是类,装饰器可以装饰类也可以装饰函数
举个例子
计算函数执行时间的装饰器
def count(func):
def inner():
starttime=datetime.now()
func()
endtime=datetime.now()
print("{}的执行时间是{}".format(func.__name__,endtime-starttime))
print("count装饰器")
return inner
@count
def func():
print('被装饰函数')
func() #调用func函数
----------------执行结果---------------
count装饰器
被装饰函数
func的执行时间是0:00:01.000402
添加@wraps装饰保留函数相关信息
- 若内部函数未添加@wraps装饰,则被装饰函数的注释、函数名、注解、签名等信息会丢失
- 解析如下:
- 定义一个函数可以正常输出函数的注解、函数名信息
def func2(x:int)->int:
'''
func2函数功能说明文档
:param x:
:return: **5
'''
return x*5
print(func2.__name__)
print(func2.__doc__)
print(func2.__annotations__)
---------------执行结果----------
func2
func2函数功能说明文档
:param x:
:return: **5
{'x': <class 'int'>, 'return': <class 'int'>}
- 装饰器装饰过后执行结果
@count
def func2(x:int)->int:
'''
func2函数功能说明文档
:param x:
:return: **5
'''
return x*5
---------------执行结果----------
inner
None
{}
- 对内部函数添加@wraps装饰,如下,即可正常输出func2函数的相关信息
from functools import wraps
def count(func):
@wraps(func) #添加wraps装饰
def inner():
starttime=datetime.now()
func()
endtime=datetime.now()
print("{}的执行时间是{}".format(func.__name__,endtime-starttime))
print("count装饰器")
return inner
定义通用装饰器
- 意义:对于被装饰的函数,不清楚具体有什么参数,以便于装饰器可适应更多的函数
- 实现:函数的参数定义为不定长参数(*args,**kwargs)
def count(func):
@wraps(func)
def inner(*args,**kwargs): #参数
starttime=datetime.now()
time.sleep(1)
result=func(*args,**kwargs) #参数
endtime=datetime.now()
print('{}的执行时间是:{}'.format(func.__name__,endtime-starttime) )
return result
print("count装饰器")
return inner
@count
def func():
time.sleep(1)
print('被装饰函数')
@count
def func2(x:int)->int:
'''
func2函数功能说明文档
:param x:
:return: **5
'''
return x*5
print('调用func{}'.format("*"*20))
func() #调用func函数
print('调用func2{}'.format("*"*20))
func2(10)
----------------执行结果----------------
count装饰器
count装饰器
调用func********************
被装饰函数
func的执行时间是:0:00:02.000744
调用func2********************
func2的执行时间是:0:00:01.000181
- 注意:对于被装饰的函数有return返回值,装饰器中必须要把被装饰的函数返回值进行return(
result=func(*args,**kwargs)
和return result
),调用被装饰函数时才能获取到值
带参的装饰器
- 意义:根据不同的参数来选择不同的装饰器
- 如下,新增加一个功能,但是只有开关开启的时候才会执行对应的代码,如果开关是关闭的则不执行
def Decor(Switch=False):
def outer(func):
@wraps(func)
def inner(*args,**kwwargs):
if Switch:
GetInfo()
func(*args,**kwwargs)
return inner
return outer
def GetInfo():
print("开关开启时才会调用")
@Decor(Switch=True)
def func():
print("被装饰函数")
func()
---------------执行结果--------------
开关开启时才会调用
被装饰函数
装饰器装饰类
如下,单例类(只有一个实例)的实现
def singleton(cls):
instance={}
def _singleton(*args,**kwargs):
if cls not in instance: #判断是否有实例化对象,没有则创建,有则直接返回
instance[cls]=cls(*args,**kwargs)
return instance[cls]
return _singleton
@singleton
class Test():
def __init__(self,a):
self.a=a
x=Test(1) is Test(2) #结果为True
等同于
class TestSingle():
instance={}
def __new__(cls,*args,**kwargs):
if not cls.instance:
cls.instance=super().__new__(cls) #调用父类创建实例
return cls.instance
def __init__(self,a):
self.a=a
类装饰器
- 初始化的时候将被装饰对象函数传递给装饰器类
- 调用装饰器类中的__call__()函数实现对被装饰对象的前后处理
- 如下,func函数会被装饰成Wrapper对象
class Wrapper():
def __init__(self,fun):
'''说明文档111'''
self.fun=fun
def __call__(self,*args,**kwargs):
start=datetime.now()
result=self.fun(*args,**kwargs)
end=datetime.now()
print('{}的执行时间是:{}'.format(self.fun.__name__, end - start))
return result
@Wrapper
def func():
print('被装饰函数')
func()
----------执行结果----
被装饰函数
func的执行时间是:0:00:00
- 类装饰器带参数,并且被装饰函数被装饰为函数
class Wrapper():
def __init__(self,switch=False):
self.switch=switch
def __call__(self,fun):
@wraps(fun)
def inner(*args,**kwargs):
if self.switch:
start=datetime.now()
result=fun(*args,**kwargs)
end=datetime.now()
print('{}的执行时间是:{}'.format(fun.__name__, end - start))
return result
return inner
@Wrapper(switch=True)
def func():
'''test'''
print('被装饰函数')
func()
------------------执行结果-----------------
被装饰函数
func的执行时间是:0:00:00.675583
类中函数实现为装饰器
- 被装饰为函数
class Wrapper():
def DecorOne(fun): #此方法相当于普通函数,类名相当于命名空间,通过@Wrapper.DecorOne调用
@wraps(fun)
def inner(*args, **kwargs):
starttime = datetime.now()
time.sleep(1)
result = fun(*args, **kwargs)
endtime = datetime.now()
print('{}的执行时间是:{}'.format(fun.__name__, endtime - starttime))
return result
return inner
@Wrapper.DecorOne
def fun():
print('被装饰函数')
fun()