Python迭代器和生成器
1.迭代器
迭代:可以将某个数据集内的数据“一个挨着一个的取出来”
for i in range(1, 10, 2): # in 后面的对象必须是一个可迭代的 print(i) # 从可迭代对象中将元素一个一个取出
""" 判断是否可迭代 """ from collections import Iterable str1 = 'adc' l = [1, 2, 3, 4] t = (1, 2, 3, 4) d = {1: 2, 3: 4} s = {1, 2, 3, 4} print(isinstance(str1, Iterable)) print(isinstance(l, Iterable)) print(isinstance(t, Iterable)) print(isinstance(d, Iterable)) print(isinstance(s, Iterable)) # True int1 = 1234 print(isinstance(int1, Iterable)) # False
2.可迭代协议
可以被迭代要满足的要求就叫做可迭代协议。内部实现了__iter__方法。
print(dir(str)) # 可迭代,内部要有一个__iter__()方法 print(str1.__iter__())
#['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__iter__', '__le__', '__len__', '__lt__', '__mod__', '__mul__', '__ne__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__rmod__', '__rmul__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'capitalize', 'casefold', 'center', 'count', 'encode', 'endswith', 'expandtabs', 'find', 'format', 'format_map', 'index', 'isalnum', 'isalpha', 'isdecimal', 'isdigit', 'isidentifier', 'islower', 'isnumeric', 'isprintable', 'isspace', 'istitle', 'isupper', 'join', 'ljust', 'lower', 'lstrip', 'maketrans', 'partition', 'replace', 'rfind', 'rindex', 'rjust', 'rpartition', 'rsplit', 'rstrip', 'split', 'splitlines', 'startswith', 'strip', 'swapcase', 'title', 'translate', 'upper', 'zfill']
#<str_iterator object at 0x0000000000A6DB38>
str_iterator
iterator 就是迭代器
str1 = 'abc' dir(str1) # 列出所有字符串实现的方法 set1 = set(dir(str1)) set2 = set(dir(str1.__iter__())) print(set2 - set1) # {'__length_hint__', '__next__', '__setstate__'}
迭代器多了三个方法
"""迭代器中的方法作用""" str1 = 'abc' # 获取迭代器 iter_1 = str1.__iter__() # 获取迭代器中元素的长度 print(iter_1.__length_hint__()) # 3 # 根据索引值指定从哪里开始迭代 print(iter_1.__setstate__(1)) # None # 一个一个的取值 print(iter_1.__next__()) # b for 循环内部调用 实现一个一个取值
自己实现迭代取数:
str1 = 'abc' # 获取迭代器 iter1 = str1.__iter__() # 循环取出 while 1 : a = iter1.__next__() print(a) # a # b # c # # Traceback (most recent call last): # File "E:/Python/d01/函数.py", line 8, in <module> # a = iter1.__next__() # StopIteration
异常机制处理异常:
str1 = 'abc' # 获取迭代器 iter1 = str1.__iter__() # 循环取出 while 1: try: a = iter1.__next__() print(a) except StopIteration: break # a # b # c
3.生成器
实现迭代器功能的东西就是生成器
Python中提供的生成器: 1.生成器函数:常规函数定义,但是,使用yield语句而不是return语句返回结果。yield语句一次返回一个结果,在每个结果中间,挂起函数的状态,以便下次从它离开的地方继续执行 2.生成器表达式:类似于列表推导,但是,生成器返回按需产生结果的一个对象,而不是一次构建一个结果列表 生成器Generator: 本质:迭代器(所以自带了__iter__方法和__next__方法,不需要我们去实现) 特点:惰性运算,开发者自定义
生成器函数
1.生成器函数:一个包含yield关键字的函数就是一个生成器函数。 2.yield与reduce区别: yield可以为我们从函数中返回值,但是yield又不同于return,return的执行意味着程序的结束,调用生成器函数不会得到返回的具体的值, 而是得到一个可迭代的对象。每一次获取这个可迭代对象的值,就能推动函数的执行,获取新的返回值。直到函数执行结束。
def genrator_f1(): a = 1 print('a变量') yield a b = 2 print('b变量') yield b g1 = genrator_f1() # g1获取的是生成器 print(g1.__next__()) print(g1.__next__()) print(g1.__next__()) # a变量 # 1 # b变量 # 2 # Traceback (most recent call last): # File "E:/Python/d01/test.py", line 14, in <module> # print(g1.__next__()) # StopIteration
生成器的优点:不会在内存中瞬间生成很多数据
def produce(): for i in range(10): yield "生产序列号:%d" % i # 获取生成器 pro_g = produce() print(pro_g.__next__()) # 一个一个获取 print(pro_g.__next__()) print(pro_g.__next__()) num = 0 # 批量获取 for i in pro_g: print(i) num += 1 if num == 5: break # 生产序列号:0 # 生产序列号:1 # 生产序列号:2 # 生产序列号:3 # 生产序列号:4 # 生产序列号:5 # 生产序列号:6 # 生产序列号:7
实现日志实时监控: Linux tail -f
import time def tail(filename): with open(filename,mode='r',encoding='utf-8') as f: f.seek(0, 2) # 从文件末尾算起 while True: line = f.readline() # 读取文件中新的文本行 if not line: time.sleep(1) continue yield line tail_g = tail('C:\\Users\\18047463\\Desktop\\test.txt') for line in tail_g: print(line.strip())
实时计算平均数:
def averager(): total = 0.0 count = 0 average = None while 1: term = yield average total += term count += 1 average = total / count g_avg = averager() g_avg.__next__() # 初始化 while 1: num = input(">>>") if num == 'q': break print(g_avg.send(int(num)))
初始化使用装饰器:
from functools import wraps def init(func): @wraps(func) def inner(*args, **kwargs): g = func(*args, **kwargs) g.__next__() return g return inner @init def averager(): total = 0.0 count = 0 average = None while 1: term = yield average total += term count += 1 average = total / count g_avg = averager() while 1: num = input(">>>") if num == 'q': break print(g_avg.send(int(num)))
def gen1(): for c in 'AB': yield c for i in range(3): yield i print(list(gen1())) def gen2(): yield from 'AB' yield from range(3) print(list(gen2()))
列表推导式和生成器表达式
egg_list=['鸡蛋%s' %i for i in range(10)] #列表解析 print(egg_list) # ['鸡蛋0', '鸡蛋1', '鸡蛋2', '鸡蛋3', '鸡蛋4', '鸡蛋5', '鸡蛋6', '鸡蛋7', '鸡蛋8', '鸡蛋9'] laomuji=('鸡蛋%s' %i for i in range(10)) #生成器表达式 相比列表解析,更加节省内存 print(laomuji) # <generator object <genexpr> at 0x00000000013F8780> print(next(laomuji)) #next本质就是调用__next__ print(laomuji.__next__()) print(next(laomuji))