一、闭包
1.概念:
① 闭包只存在于嵌套函数中
②和嵌套函数有区别,闭包必须存在内层函数对外层函数的非全局变量的引用
2.闭包的用处:保证数据安全
3.自由变量:
def wrapper():
a = 1
def inner():
print(a)
return inner
ret = wrapper()
# 是闭包,内层函数引用的了外层函数的变量a,
#此时a称作自由变量,存在于一个独立的内存空间中,他不会随着函数的结束而消失
def wrapper(a,b):
def inner():
print(a)
print(b)
return inner
a = 2
b = 3
ret = wrapper(a,b) # 也是闭包,内部函数inner引用了外部函数wrapper的变量a,b
4.判断闭包:就是判断这个函数有没有自由变量
ret = wrapper(a,b)
print(ret.__code__.co_freevars) # ('a', 'b')
二、装饰器
在不改变原函数的代码以及调用方式的前提下,为其增加新的功能。遵循开放封闭原则
1.最基本的装饰器
# 需求:计算一个函数的运行时间
import time
# 装饰器函数
def wrapper(func):
def inner():
start_time = time.time() # 函数执行前的操作
func()
end_time = time.time() # 函数执行后的操作
print(f'函数执行时间{end_time-start_time}')
return inner
# @wrapper 此处相当于 test_func = wrapper(test_func)
@wrapper
def test_func():
time.sleep(1)
print("测试一些时间")
test_func()
# 测试一些时间
# 函数执行时间1.002511978149414
2.被装饰函数带有返回值
# 需求变了,test_func带有返回值
import time
# 装饰器函数
def wrapper(func):
def inner():
start_time = time.time() # 函数执行前的操作
ret = func() # 此处将函数的返回值赋给ret
end_time = time.time() # 函数执行后的操作
print(f'函数执行时间{end_time-start_time}')
return ret # 将函数的返回值进行返回
return inner
# @wrapper 此处相当于 test_func = wrapper(test_func)
@wrapper
def test_func():
time.sleep(1)
msg = "我是返回值"
return msg
a = test_func()
print(a)
# 函数执行时间1.004417896270752
# 我是返回值
3.被装饰函数带有参数
# 需求又变了,test_func函数带有参数
import time
# 装饰器函数
def wrapper(func):
def inner(*args, **kwargs):
# 函数定义阶段 *是函数的聚合,聚合成元祖 (x,y)
start_time = time.time() # 函数执行前的操作
ret = func(*args) # 函数执行阶段 *是打散 func(*args) -> func(*(x,y)) -> func(x,y)
end_time = time.time() # 函数执行后的操作
print(f'函数执行时间{end_time-start_time}')
return ret
return inner
# @wrapper 此处相当于 test_func = wrapper(test_func)
@wrapper
def test_func(x, y):
time.sleep(1)
msg = x + y
return msg
a = test_func(1, 2)
print(a)
# 函数执行时间1.0041322708129883
# 3
4.装饰器带有参数
# 需求增加了,增加一个打印日志功能,通过一个参数控制是否需要打印
import time
# 装饰器函数
def wrapper(func):
def inner(*args, **kwargs):
# 函数定义阶段 *是函数的聚合,聚合成元祖 (x,y)
start_time = time.time() # 函数执行前的操作
ret = func(*args) # 函数执行阶段 *是打散 func(*args) -> func(*(x,y)) -> func(x,y)
end_time = time.time() # 函数执行后的操作
print(f'函数执行时间{end_time-start_time}')
return ret
return inner
# 带有参数的装饰器就是在原有装饰器的基础上在套一层
def log(isneed):
def wrapper(func):
def inner(*args, **kwargs):
ret = func(*args)
if isneed:
print(f"函数名:{func.__name__}")
else:
print("此时不需要打印")
return ret
return inner
return wrapper
#多装饰器,采取就近原则作为执行顺序
@log(isneed=True)
@wrapper
def test_func(x, y):
time.sleep(1)
msg = x + y
return msg
a = test_func(1, 2)
print(a)
# 函数执行时间1.004870891571045
# 函数名:inner
# 3
5.@wraps
上一个例子打印出来的函数名是inner,其实最初我们的函数名是test_func,为了避免这种情况,用到了@wraps装饰器
import time
from functools import wraps
# 装饰器函数
def wrapper(func):
@wraps(func)
def inner(*args, **kwargs):
# 函数定义阶段 *是函数的聚合,聚合成元祖 (x,y)
start_time = time.time() # 函数执行前的操作
ret = func(*args) # 函数执行阶段 *是打散 func(*args) -> func(*(x,y)) -> func(x,y)
end_time = time.time() # 函数执行后的操作
print(f'函数执行时间{end_time-start_time}')
return ret
return inner
def log(isneed):
def wrapper(func):
@wraps(func)
def inner(*args, **kwargs):
ret = func(*args)
if isneed:
print(f"函数名:{func.__name__}")
else:
print("此时不需要打印")
return ret
return inner
return wrapper
@log(isneed=True)
@wrapper
def test_func(x, y):
time.sleep(1)
msg = x + y
return msg
a = test_func(1, 2)
print(a) #此时打印出来的函数名为test_func, 需要注意的是,如果有多个装饰器,每一个都得用@wraps 否则打印出函数名还是inner
网友评论