12 装饰器与迭代器
1 什么是装饰器
装饰器就是装饰别人的工具,具体是指为被装饰者添加新功能
装饰器-》函数
被装饰者-》函数
2 为何要用装饰器
装饰器的核心思想:(开放封闭原则)
在不修改被装饰者源代码以及调用方式的前提下,为被装饰者添加新功能
3 如何实现装饰器
可以用闭包函数去实现装饰器
一、装饰器的实现
# 被装饰者 # import time # # def index(): # print('welcome to index page') # time.sleep(3) # # index() # 方案一:问题-》修改了被装饰者的源代码 # import time # # def index(): # start = time.time() # print('welcome to index page') # time.sleep(3) # stop = time.time() # print(stop - start) # # index() # 方案二:问题-》会造成代码冗余 # import time # # def index(): # print('welcome to index page') # time.sleep(3) # # start = time.time() # index() # stop = time.time() # print(stop -start) # # start = time.time() # index() # stop = time.time() # print(stop -start) # # start = time.time() # index() # stop = time.time() # print(stop -start) # # 方案三:问题-》修改了被装饰对象的调用方式 # import time # # def index(): # print('welcome to index page') # time.sleep(3) # # def wrapper(func): # start = time.time() # func() # stop = time.time() # print(stop -start) # # wrapper(index) # # 方案四:我们用wrapper函数赋值给原函数名index,wrapper应该与原函数保持一致,但是现在的问题是不一致 # import time # # def index(): # print('welcome to index page') # time.sleep(3) # # def outter(func): # func = 最原始那个index函数的内存地址 # def wrapper(): # start = time.time() # func() # stop = time.time() # print(stop -start) # return wrapper # # index = outter(index) # f=outter(最原始那个index函数的内存地址) # # f=函数wrapper的内存地址 # # # print(f) # # index() # 方案四:让wrapper的参数与返回值与被装饰者保持一致 # import time # # def index(x,y,z): # print('welcome to index page',x,y) # time.sleep(3) # return 123 # # # def outter(func): # func = 最原始那个index函数的内存地址 # def wrapper(*args,**kwargs): # start = time.time() # res = func(*args,**kwargs) # stop = time.time() # print(stop -start) # return res # return wrapper # # index = outter(index) # f=outter(最原始那个index函数的内存地址) # # f=函数wrapper的内存地址 # # # res = index(111,222,333) # res = wrapper(111,222,333) # print(res)
二、装饰器语法糖
import time from functools import wraps def outter(func): @wraps(func) def wrapper(*args, **kwargs): start = time.time() res = func(*args, **kwargs) stop = time.time() print(stop - start) return res return wrapper @outter # index = outter(index) def index(x, y, z): """index函数的文档注释""" print('welcome to index page', x, y) time.sleep(3) return 123 # res = index(111, 222, 333) # print(res) # print(index) help(index)
三、装饰器的模板
# def outter(func): # def wrapper(*args,**kwargs): # res = func(*args,**kwargs) # return res # return wrapper
案例:
案例1
# def sayhi(func): # def wrapper(*args,**kwargs): # print('hello') # res = func(*args,**kwargs) # return res # return wrapper 案例2 # def auth(func): # def wrapper(*args,**kwargs): # u = input('username>>>: ').strip() # p = input("password>>>: ").strip() # if u == 'egon' and p == '123': # res = func(*args,**kwargs) # return res # else: # print("认证失败") # return wrapper # # @auth # def index(): # print('index=========>') # # index()
四、迭代器
1.迭代器指的是迭代取值的工具
什么是迭代???
迭代是一个重复的过程,但是每一次重复都是基于上一次结果而继续的
# names = ['egon','tom','lili','jack','xxx'] # msg = "hello world" dic = {'k1':111,'k2':2222,'k3':33333} def foo(xxx): i = 0 while i < len(xxx): print(xxx[i]) i += 1 # foo(names) # foo(msg) foo(dic)
2.为何要用迭代器
1 为了找到一种统一迭代取值方案(适用于str、list、tuple、dict、set,文件对象)
2 节省内存
3.如何用迭代器
可迭代的对象iterable:
内置有__iter__方法的对象(str、list、tuple、dict、set,文件对象)
迭代器对象iterator:
内置有__iter__方法
内置有__next__方法
# "abc".__iter__() # [1,23].__iter__() # (1,2,3).__iter__() # {'k1':111}.__iter__() # {1,2,3}.__iter__() # f = open('a.txt',mode='wt') # f.__iter__() # print(len("abc")) # "abc".__len__() # dic = {'k1':1111,'k2':2222,'k3':3333} # iter_dic = dic.__iter__() # iter_dic=iter(dic) # # # print(iter_dic) # print(iter_dic.__next__()) # print(next(iter_dic)) # print(iter_dic.__next__()) # print(iter_dic.__next__()) # # print(iter_dic.__next__()) # 报错 # # new_iter = dic.__iter__() # print(new_iter.__next__()) # msg = "hello world" # iter_msg = msg.__iter__() # # print(iter_msg.__next__()) # print(iter_msg.__next__()) # print(iter_msg.__next__()) # print(iter_msg.__next__()) dic = {'k1': 1111, 'k2': 2222, 'k3': 3333,'k4':4444,'k5':5555} # iter_dic = iter(dic) # iter_dic.__next__() # print(iter_dic.__iter__().__iter__().__iter__() is iter_dic) # while True: # try: # print(next(iter_dic)) # except StopIteration: # break # for x in dic: # print(x) # 例1: # dic = {'k1': 1111, 'k2': 2222, 'k3': 3333,'k4':4444,'k5':5555} # # iter_dic = iter(dic) # for k in iter_dic: # print(k) # print('='*50) # # iter_dic = iter(dic) # for k in iter_dic: # print(k) # 例2 # with open('a.txt',mode='rt',encoding='utf-8') as f: # for line in f: # print(line) # print('='*50) # for line in f: # print(line) l = [1,2,3,4,5,6,7,8,9] iter_l=iter(l)
4.自定义迭代器
yield可以返回多次值
def func(): print('hello1') print('hello1') print('hello1') yield 111 print('hello2') print('hello2') print('hello2') yield 222 print('hello3') print('hello3') print('hello3') print('hello3') yield 333 print('hello4') print('hello4') print('hello4') print('hello4')
函数内但凡出现yield语法,我们再调用函数就不会立即触发函数体代码运行,会返回一个生成器对象,生成器对象就是一种自定义的迭代器
g = func() # print(g) # g.__iter__() # g.__next__() res=next(g) print(res) res=next(g) print(res) res=next(g) print(res) next(g)
叠加多个装饰器
def deco1(func1): # func1=函数wrapper2的内存地址 def wrapper1(*args,**kwargs): print('=========>wrapper1') res1 = func1(*args,**kwargs) return res1 return wrapper1 def deco2(func2): # func2=函数wrapper3的内存地址 def wrapper2(*args,**kwargs): print('=========>wrapper2') res2 = func2(*args,**kwargs) return res2 return wrapper2 def deco3(func3): # func3 = 最原始那个index函数的内存地址 def wrapper3(*args,**kwargs): print('=========>wrapper3') res3 = func3(*args,**kwargs) return res3 return wrapper3 # index=函数wrapper1的内存地址 @deco1 # deco1(函数wrapper2的内存地址)->函数wrapper1的内存地址 @deco2 # deco2(函数wrapper3的内存地址)->函数wrapper2的内存地址 @deco3 # deco3(最原始那个index函数的内存地址)->函数wrapper3的内存地址 def index(): print('=------------>index') return 123 res = index() print(res) # print(index)
迭代器实现range功能
# def my_range(start, stop, step): # while start < stop: # 5 < 5 # yield start # 3 # start += step # start = 5 # # # g = my_range(1,5,2)
五、for循环的工作原理: