Python自学之路之day12-装饰器
介绍装饰器之前,我们先了解下以下函数打印结果。
1) def base(): print("我是base函数") def bar(): print("我是bar函数") bar = base bar() 打印结果: 我是base函数 2) def func(): def inner(): print("我是inner函数") return inner v = func() print(v) 打印结果: (<function func.<locals>.inner at 0x00000269313A0AE8>)打印inner函数内存地址 3) def func(arg): def inner(): print(arg) return inner v1 = func(1) v2 = func(2) 4) def func(arg): def inner(): arg() return inner def fn1(): print("我是fn1函数") v1 = func(fn1) v1() 5) def func(arg): # arg = f1 def inner(): arg() # 等于执行f1函数 return inner def f1(): print(123) return 666 v1 = func(f1) #v1 == inner函数 result = v1() # 执行inner函数,inner函数包含arg(f1函数)函数执行,打印123,返回666,但是666并没变量接收 print(result) # 接收返回值,该返回值为inner的返回值,为None 打印结果: 123 None 6) def func(arg): def inner(): return arg() return inner def f1(): print(123) return 666 v1 = func(f1) # v1 == inner result = v1() # 执行inner函数,inner函数的返回值为arg(f1)函数的执行,打印123,并把666返回给inner,result == 666 print(result)
二、装饰器
## 装饰器 def func(arg): def inner(): print('before') v = arg() print('after') return v return inner def index(): print('123') return '666' #1、 # v1 = index() # 执行index函数,打印123,返回666 #2、 # v2 = func(index) # 执行func函数,返回值为inner函数,v2 == inner,此时arg == index,指向index函数地址 # index = 666 # index重新赋值为666,注意:虽然index被重新赋值,但是index函数对应的地址,并没有销毁,arg对应的就是index函数的内存地址 # v3 = v2() # v3等于inner函数的返回值。执行inner函数,首先会打印"before",v = arg(),arg = index,所以相当于执行index函数,会打印123,并将666赋值给v,接着打印after,inner函数返回v # print(v3) # 根据上面分析,v3等于inner函数的返回值,inner函数返回值为v,v == 666,因此最后会打印666 ## 打印结果 """ before 123 after 666 """ #3、 v4 = func(index) # 执行func函数,返回值为inner函数,v4 == inner,此时arg == index,指向index函数地址 index = v4 # 把v4(inner)赋值给index,这时index = inner,注意,此时的index,与之前的index并不是一个函数 index() # 执行index函数,相当于执行inner函数,首先打印"before", v = arg():等于是执行之前的index函数,此时会打印123,并把index的函数返回值赋值给v,随后打印"after",inner返回值为v ## 打印结果 """ before 123 after """ #4、根据3中的分析,可以简写为以下模式。 index = func(index) index()
最终装饰器成型:
def func(arg): def inner(): print('before') v = arg() print('after') return v return inner
# 第一步:执行func函数并将下面的函数参数传递,相当于:func(index) # 第二步:将func的返回值重新赋值给下面的函数名。 index = func(index)
@func def index(): print('123') return '666' 打印结果: before 123 after
装饰器总结:
目的:在不改变原函数的基础上,在函数执行前后自定义功能。
# 装饰器的编写 def x(func): def y(): # 前 ret = func() # 后 return ret return y # 装饰器的应用 @x def index(): return 10 @x def manage(): pass # 执行函数,自动触发装饰器了 v = index() print(v)
装饰器格式:
def 外层函数(参数): def 内层函数(*args,**kwargs): return 参数(*args,**kwargs) return 内层函数
装饰器应用格式:
@外层函数 def index(): pass index()
三、带参数装饰器
# ################## 普通装饰器 ##################### def wrapper(func): def inner(*args,**kwargs): print('调用原函数之前') data = func(*args,**kwargs) # 执行原函数并获取返回值 print('调用员函数之后') return data return inner @wrapper def index(): pass # ################## 带参数装饰器 ##################### def x(counter): def wrapper(func): def inner(*args,**kwargs): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner return wrapper @x(9) def index(): pass
分析:
def x(counter): def wrapper(func): def inner(*args,**kwargs): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner return wrapper # 第一步:执行 v1 = x(9) # 第二步:ret = v1(index) # 第三步:index = ret @x(9) def index(): pass
练习1:
# 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,把每次结果添加到列表中,最终返回列表。 def xxx(counter): print('x函数') def wrapper(func): print('wrapper函数') def inner(*args,**kwargs): v = [] for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 v.append(data) return v return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v)
练习2:
# 写一个带参数的装饰器,实现:参数是多少,被装饰的函数就要执行多少次,并返回最后一次执行的结果 def xxx(counter): print('x函数') def wrapper(func): print('wrapper函数') def inner(*args,**kwargs): for i in range(counter): data = func(*args,**kwargs) # 执行原函数并获取返回值 return data return inner return wrapper @xxx(5) def index(): return 8 v = index() print(v)
模板:
def x(counter): print('x函数') def wrapper(func): print('wrapper函数') def inner(*args,**kwargs): if counter: return 123 return func(*args,**kwargs) return inner return wrapper @x(True) def fun990(): pass @x(False) def func10(): pass
练习题3:
# 请为以下函数编写一个装饰器,添加上装饰器后可以实现:执行 read_userinfo 函时,先检查文件路径是否存在,如果存在则执行后,如果不存在则 输入文件路径不存在,并且不再执行read_userinfo函数体中的内容,再讲 content 变量赋值给None。 def read_userinfo(path): file_obj = open(path,mode='r',encoding='utf-8') data = file_obj.read() file_obj.close() return data content = read_userinfo('文件路径') 答案: import os def warper(fn): def inner(*agrs,**kwargs): if not os.path.exists("../day13"): print("路径不存在") return None v = fn(*agrs,**kwargs) return v return inner @warper def read_userinfo(path): file_obj = open(path,mode='r',encoding='utf-8') data = file_obj.read() file_obj.close() return data content = read_userinfo('../day13/作业.py') print(content)

浙公网安备 33010602011771号