一、迭代器
1、为何要有迭代器?
对于序列类型:字符串、列表、元组,我们可以使用索引的方式迭代取出其包含的元素。但对于字典、集合、文件等类型是没有索引的,若还想取出其内部包含的元素,则必须找出一种不依赖于索引的迭代方式,这就是迭代器
2、什么是可迭代对象?
可迭代对象指的是内置有__iter__方法的对象,即obj.__iter__,如下 'hello'.__iter__ #字符串 (1,2,3).__iter__ #元组 [1,2,3].__iter__ #列表 {'a':1}.__iter__ #字典 {'a','b'}.__iter__ #集合 open('a.txt').__iter__ #文件
3、什么是迭代器?
可迭代对象执行obj.__iter__()得到的结果就是迭代器对象 而迭代器对象指的是即内置有__iter__又内置有__next__方法的对象
但是,list
、dict
、str
等可迭代对象并没有__next__()方法,所以它不是迭代器
可以把使用iter()
函数把list
、dict
、str
等可迭代对象变成迭代器
from collections import Iterator a=isinstance([],Iterator) b=isinstance((),Iterator) c=isinstance({},Iterator) d=isinstance('abc',Iterator) e=isinstance((i for i in range(10)),Iterator) f=isinstance(100,Iterator) print(a) print(b) print(c) print(d) print(e) print(f) 输出: False False False False True False
str1='hello' #字符串 tuple1=(1,2,3) #元组 list1=[1,2,3] #列表 dict1={'a':1} #字典 set1={'a','b'} #集合 #使用iter()方法把可迭代对象变成迭代器 iter_str=iter(str1) iter_tuple=iter(tuple1) iter_list=iter(list1) iter_dict=iter(dict1) iter_set=iter(set1) print(iter_str.__next__()) print(iter_tuple.__next__()) print(iter_list.__next__()) print(iter_dict.__next__()) print(iter_set.__next__())
4、for循环
#基于for循环,我们可以完全不再依赖索引去取值了 dic={'a':1,'b':2,'c':3} for k in dic: print(dic[k]) #for循环的工作原理 #1:执行in后对象的dic.__iter__()方法,得到一个迭代器对象iter_dic #2: 执行next(iter_dic),将得到的值赋值给k,然后执行循环体代码 #3: 重复过程2,直到捕捉到异常StopIteration,结束循环
5、迭代器的缺点
#优点: - 提供一种统一的、不依赖于索引的迭代方式 - 惰性计算,节省内存 #缺点: - 无法获取长度(只有在next完毕才知道到底有几个值) - 一次性的,只能往后走,不能往前退
二、生成器
1、什么是生成器?
可以理解为一种数据类型、这种数据类型实现了迭代器协议(其他的数据类型需要调用自己内置的__iter__()方法才可以),所以生成器就是可迭代对象。
2、生成器在Python中的表现形式
1、生成器函数 常规函数定义、但是是使用yield语句而不是使用return返回结果 yield语句一次返回一个结果、在每个结果中间挂起函数的状态 2、生成器表达式 类似于列表推导、但是生成器返回按需产生一个对象而不是一次构建一个结果列表
3、列表生成式
现在有一个需求,需要把列表[0,1,2,3,4,5,6,7,8,9]里的每个元素都加1,怎么实现?有以下几种方式: list1=[0,1,2,3,4,5,6,7,8,9] for index,i in enumerate(list1): list1[index]=i+1 print(list1) #原值修改 或者 a=[] for i in range(10): a.append(i*2) print(a)
列表生成式写法
num_list = [ i*2 for i in range(10) ] #或者赋值 num_list = [ "数字%s"%i for i in range(10) ] print(num_list) #输出: ['数字0', '数字1', '数字2', '数字3', '数字4', '数字5', '数字6', '数字7', '数字8', '数字9'] #结合三元表达式 num_list = [ "数字%s"%i for i in range(10) if i > 5] print(num_list) #输出: ['数字6', '数字7', '数字8', '数字9']
通过列表生成式,我们可以直接创建一个列表。但是,受到内存限制,列表容量肯定是有限的。而且,创建一个包含100万个元素的列表,不仅占用很大的存储空间,如果我们仅仅需要访问前面几个元素,那后面绝大多数元素占用的空间都白白浪费了。
所以,如果列表元素可以按照某种算法推算出来,那我们是否可以在循环的过程中不断推算出后续的元素呢?这样就不必创建完整的list,从而节省大量的空间。
在Python中,这种一边循环一边计算的机制,称为生成器:generator。
要创建一个generator,有很多种方法。第一种方法很简单,只要把一个列表生成式的[]
改成()
,就创建了一个生成器:
num_list = ("数字%s"%i for i in range(10) if i > 5) print(num_list.__next__()) print(num_list.__next__()) print(num_list.__next__()) #输出: 数字6 数字7 数字8
4、yield生成器函数
只要函数中存在yield,这个函数就是一个生成器函数
yield功能:1、相当于return一个返回值。2、保存函数的状态,以便下次从它离开的地方执行
def test(): yield 1 yield 2 yield 3 yield 4 num=test() print(num.__next__()) print(num.__next__()) print(num.__next__()) print(num.__next__()) #输出:1 # 2 # 3 # 4
def fib(max): n,a,b=0,0,1 while n<max: # print(b) yield b a,b=b,a+b n=n+1 gen=fib(10) for i in gen: print(i)
import time def consumer(name): print("%s准备吃包子了"%name) while True: baozi=yield print('包子[%s]来了,被%s吃了'%(baozi,name)) # c1=consumer('lily') # c1.__next__() # # c1.send('韭菜') def producer(name): c=consumer('A') c2=consumer('B') c.__next__() c2.__next__() print('%s开始做包子了'%name) for i in range(10): time.sleep(1) print('做了两个包子') c.send(i) c2.send(i) producer('Tom')
#yield相当于return控制的是函数的返回值 #x=yield的另外一个特性是,接收send()传过来的值赋值给yield def func(): print("yield来啦") name=yield print("yield接收send传参-%s"%name) yield 2 print("下一步yield执行啦") test=func() print(test.__next__()) # 这一步打印的yield返回值是None res=test.send('Tom') #把Tom传给yield然后赋值给name,执行到yield 2返回 send相当于一次next操作 print(res)
三、装饰器
定义:装饰器本质上是一个函数
功能:就是为其他函数添加附加功能
原则:1.不能修改被装饰的函数的源代码
2.不能修改被装饰的函数的调用方式
#实现装饰器的知识: #1.函数即变量 #2.高阶函数:满足下面两个条件 #a: 把一个函数名当做实参传给另外一个函数 (在不修改被装饰函数源代码的情况下为其添加功能) #b: 返回值中包含函数名(不改变函数的调用方式) #3.嵌套函数 #高阶函数+嵌套函数+闭包 =装饰器
import time def timer(func): def deco(*args,**kwargs): start_time=time.time() func(*args,**kwargs) #会往上一级找 end_time=time.time() print('the func run time is %s'%(end_time-start_time)) return deco @timer def test1(name): time.sleep(3) print('in the test1') print(name) @timer def test2(): time.sleep(3) print('in the test2') #test1=timer(test1) #test2=timer(test2) test1('sunhao') test2()
import time def timmer(func): def wrapper(): start_time=time.time() result=func() #拿到func函数的返回值 stop_time=time.time() print('the func run time is %s'%(stop_time-start_time)) return result #再返回 return wrapper def test(): time.sleep(1) print('in the test1') res=timmer(test) #返回的是wrapper的地址 timmer(test) 相当于@timmer res() #执行的是wrapper函数 #把timmer(test)赋值给test,再执行test(),就没修改被装饰的函数的调用方式
import time def timmer(func): def wrapper(*args,**kwargs): start_time=time.time() res=func(*args,**kwargs) stop_time=time.time() print('run time is %s' %(stop_time-start_time)) return res return wrapper @timmer #相当于foo=timmer(foo) def foo(): time.sleep(3) print('from foo') foo()
user_list=[{'name':'allen','password':'123456'}, {'name':'lucy','password':'123456'}, {'name':'lily','password':'123456'} ] current_user={'username':None,'login':False} def auth_type(func): def wrapper(*args,**kwargs): if current_user['username'] and current_user['login']: ret = func(*args,**kwargs) return ret username=input("请输入用户名:").strip() password=input("请输入密码:").strip() for name in user_list: if name['name']== username and name['password'] == password: current_user['username']=username current_user['login']=True ret = func(*args, **kwargs) return ret else: print("用户名密码错误") return wrapper @auth_type def index(name): print("欢迎来%s购物商城"%name) @auth_type def shopping(): print("shopping 吧") index('京东') shopping()
user_list=[{'name':'allen','password':'123456'}, {'name':'lucy','password':'123456'}, {'name':'lily','password':'123456'} ] current_user={'username':None,'login':False} def outer(auth_type): def auth_func(func): def wrapper(*args,**kwargs): print("认证类型是%s"%auth_type) if auth_type =="file": if current_user['username'] and current_user['login']: ret = func(*args,**kwargs) return ret username=input("请输入用户名:").strip() password=input("请输入密码:").strip() for name in user_list: if name['name']== username and name['password'] == password: current_user['username']=username current_user['login']=True ret = func(*args, **kwargs) return ret else: print("用户名密码错误") elif auth_type =='mysql': ret = func(*args, **kwargs) return ret return wrapper return auth_func @outer(auth_type='file') #auth_func=outer(auth_type='filedb') def index(name): print("欢迎来%s购物商城"%name) @outer(auth_type='mysql') def shopping(): print("shopping 吧") index('京东') shopping()