装饰器
闭包
函数内部作用域定义的变量和函数,只能在函数内部使用(外部无法直接访问和修改)
函数外部要使用局部作用域内的数据,只能通过return返回出去
闭包函数 = 函数 + 保存引用数据的封闭作用域`
闭包的特征:
- 函数中嵌套一个函数
- 外层函数rertun返回 内层函数
- 内层函数有引用 **外部作用域** 的非全局变量
简单的闭包:
装饰器:
定义:本质是函数,(装饰其他函数)就是为其他函数添加附加功能
作用:在不更改原功能函数内部代码,并且不改变调用方法的情况下为源代码添加新功能
原则:
1、不能修改被装饰函数的源代码
2、不能修改被装饰的函数的调用方式
实现装饰器知识储备
1、函数既变量
2、高阶函数
把函数名当作一个实参传递给另一个函数
返回值中包含函数名
3、嵌套函数
高阶函数+嵌套函数=装饰器
"""
基础装饰器:
func_demo(2,3)
输出:
-----装饰器的扩展功能--1----
a除B的结果为: 0.6666666666666666
装饰器的副作用:
print(func_demo.__name__) 打印函数的名称
print(func_demo.__doc__) 打印函数的注释说明
在函数func_demo使用装饰器func后,打印func_demo的函数名,和函数说明,会打印出wrapper的函数名和函数说明
为了消除这一副作用,需要引入模块 :from functools import wraps
装饰器装饰类
注意:
在装饰类的时候在调用原来类的对象的时候,一定要用一个变量接受,然后对变量进行返回,不加return类就不能创建对象
普通的通用装饰器
1 import time 2 3 4 def fun1(ff): 5 def count_time(*args, **kwargs): 6 start_time = time.time() 7 res = ff(*args, **kwargs) 8 end_time = time.time() 9 print('函数执行的时间:', end_time-start_time) 10 return res 11 return count_time 12 13 @fun1 # work1=count_time(work1) 14 def work1(): 15 time.sleep(0.5) 16 print("这是work1") 17 18 @fun1 # work2=count_time(work2) 19 def work2(a,b): 20 time.sleep(0.8) 21 print("work2函数的功能",a+b) 22 23 work1() 24 work2(1,2)
可以传参数的装饰器
def decorator(name):
"""最外层的参数是装饰器的参数"""
def wrapper1(func):
"""第二次定义的参数,接收被装饰的函数"""
def wrapper2(*args, **kwargs):
print("-----装饰器的扩展功能代码111")
print("装饰器传入的参数name:", name)
# 执行被装饰的函数
res = func(*args, **kwargs)
print("-----装饰器的扩展功能代码222")
return res
return wrapper2
return wrapper1
@decorator('tom') # work = decorator('tom')(work) decorator('tom')等于wrapper1
def work():
print('--------------work------------------')
缓存装饰器lru_cache:
256的单位是bytes
对同一个函数相同的入参执行的结果进行缓存,通常用于提升递归函数的效率
例:用一个函数得,传一个int正整数,得到斐波那契数列的第几位数
输出:34
通过类实现装饰器
class Decorator(): def __init__(self, func): self.func = func def __call__(self, *args, **kwargs): print("装饰器扩展的代码") # 调用原功能函数 self.func(*args, **kwargs) @Decorator def work(a,b): # work = Decorator(work) print("--------work--------") print(a+b) work(10,30)
练习题
1、设计一个装饰器,接受一个int类型的参数number,可以用来装饰任何函数,如果函数运行的时间大于number,则打印出函数名和函数的运行时间
1 def fun1(num): 2 def fun2(ff): 3 def fun3(*args,**kwargs): 4 s_time = time.time() 5 ff(*args,**kwargs) 6 e_time = time.time() 7 run_time = e_time-s_time 8 if run_time > num: 9 print('函数运行时间:{}'.format(run_time)) 10 print('函数名{}'.format(ff.__name__)) 11 return fun3 12 return fun2 13 14 @fun1(1) 15 def work(): 16 time.sleep(2) 17 print("这是work功能") 18 19 work()
2、实现一个重运行的装饰器,可以用来装饰任何一个功能函数,只要被装饰的函数出现AssertionError,则重新执行该函数,同一个函数最多运行三次
1 def fun1(ff): 2 def fun2(*args,**kwargs): 3 for i in range(1,4): 4 try: 5 res = ff(*args,**kwargs) 6 except AssertionError as e: 7 if i==3: 8 raise e 9 else: 10 print("执行通过") 11 return res 12 # break 13 return fun2 14 15 @fun1 16 def work2(): 17 expected = 'abc' 18 res = input("请输入:") 19 assert expected == res 20 21 22 work2()