13、装饰器与迭代器

一、复习

储备知识1
def index(x,y):
   print(x,y)

def wrapper(*args,**kwargs):
   index(*args,**kwargs)  # index(1,2,z=3)

wrapper(1,2,z=3)


储备知识2
def outter():
   def wrapper():
       pass

储备知识3:
结论1:L-》E-》G-》B
结论2:名称空间的嵌套关系是在函数定义阶段扫描语法时生成的

储备知识4:
def outter():
   x = 111
   def wrapper():
       print(x)
   return wrapper


f=outter()  # f=函数wrapper的内存地址

def foo():
   x=222
   f()

foo()


储备知识5:为函数体传参的两种方案
方案一:
def wrapper(x):
   print(x)

wrapper(111)
wrapper(222)


方案二:
def outter(x):
   def wrapper():
       print(x)

   return wrapper

f = outter(111)  #f = 函数wrapper的内存地址
f()

f = outter(222)  #f = 函数wrapper的内存地址
f()

 

二、装饰器

"""
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


def sayhi(func):
   def wrapper(*args,**kwargs):
       print('hello')
       res = func(*args,**kwargs)
       return res
   return wrapper

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)

 

六、自定义迭代器


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)

 

posted @ 2021-10-09 20:35  谁笑  阅读(136)  评论(0)    收藏  举报