python迭代器和生成器详解
一.迭代:
1.什么是迭代:
迭代就是对list,tuple等数据类型进行for…in循环,这种方式叫遍历,也就是迭代。
2.什么是迭代对象:
- 可迭代对象就是从循环中依次取出来的对象。
- 常见的可迭代对象有:list,tuple,string,dict,range
- 常见的不可迭代的对象有:数字,布尔值
- 检测是否是可迭代对象的方法:isinstance(list,Iterable)
from collections import Iterable
list = [1,3,54,6]
print(isinstance(list,Iterable)) # True
3.可迭代协议:
- 可迭代协议就是内部实现了__iter__方法。其中__iter__方法就是一个迭代器,包含迭代器的对象就是可迭代对象。
- 判断方法:使用dir()函数查看是否含有__iter__。
print(dir(list))
"""输出结果"""
"""
['__add__', '__class__', '__class_getitem__', '__contains__',
'__delattr__', '__delitem__', '__dir__', '__doc__', '__eq__',
'__format__', '__ge__', '__getattribute__', '__getitem__', '__gt__',
'__hash__', '__iadd__', '__imul__', '__init__', '__init_subclass__',
'__iter__', '__le__', '__len__', '__lt__', '__mul__', '__ne__',
'__new__', '__reduce__', '__reduce_ex__', '__repr__', '__reversed__',
'__rmul__', '__setattr__', '__setitem__', '__sizeof__', '__str__',
'__subclasshook__', 'append', 'clear', 'copy', 'count', 'extend',
'index', 'insert', 'pop', 'remove', 'reverse', 'sort']
"""
4.迭代器:
- 迭代器作用:在进行遍历时,每每循环一次都会返回下一个数据,直到读完所有的数据为止。迭代器的作用就是记住访问到了第几条数据,以便于拿到下一条数据。
- 迭代器的本质:就是把存储数据和遍历数据分开来。
- 迭代器必须有__iter__和__next__方法。
- 迭代器优点:节省内存。不依赖索引取值。惰性计算。
- 迭代器的两种实现方法:
"""第一种方法"""
list = [1,3,54,6]
listiter = list.__iter__()
print(listiter.__next__())
print(listiter.__next__())
print(listiter.__next__())
"""
输出结果:
1
3
54
"""
""""第二种方法"""
list = [1,3,54,6]
listiter = iter(list)
print(next(listiter))
print(next(listiter))
"""
输出结果:
1
3
"""
- 创建一个迭代器:
class iterclass():
def __init__(self,list):
self.list = list
self.location = 0
def __iter__(self):
return self
def __next__(self):
# 判断当前位置是否小于列表的长度
if self.location < len(self.list):
item = self.list[self.location]
self.location += 1
return item
else:
raise StopIteration
list = [1,3,54,6]
iterc = iterclass(list)
print(iterc.__iter__(),"返回迭代器")
for i in iter(iterc):
print(i,"取值---")
5.for循环在循环可迭代对象时,其内部活动:
- 将可迭代对象转换为迭代器
- 使用__next__方法,进行一个一个的取值
- 捕获了StopIteration异常,取值到底之后自动结束
"""while循环实现for循环"""
list = [1,3,54,6]
listiter = iter(list)
while True:
try:
print(next(listiter))
except StopIteration:
break
二.生成器:
1.什么是生成器:
- 本质:是一个迭代器,即生成器是一种特殊的迭代器。
- 特点:惰性运算,开发者自定义。
- 生成器函数:在生成器函数中,用yield语句而不是return语句,yield语句一次返回一个结果。在其中两个结果的中间,函数是挂起的状态,以便于下次从离开的地方开始执行而不是从头开始。
- 生成器表达式:类似于列表推导式,但生成器是按需取结果,而不是一次性来构建一个结果列表。
2.生成器函数:
- 带有yeild关键字的函数就是生成器函数,yield返回的不是一个具体的值,而是一个可迭代对象。不断获取可迭代对象的值会推动函数的执行,直到函数执行完毕。
- yield和return:return执行代表着程序的结束。yield只能写在函数里,return和yield不能沟通使用。
- 想要执行生成器函数,必须调用__next__()方法
def func():
a = 1
print("生成器---1")
yield a
b = 2
print("生成器---2")
yield b
fun = func()
print(fun) #<generator object func at 0x0000024E026D89E0> 表示就是一个生成器 代表其内存地址
print(fun.__next__()) # 生成器---1 1
time.sleep(2)
print(fun.__next__()) # 生成器---2 2
fun = func()
print(fun.__next__()) # 0
print(fun.__next__()) # 1
print(fun.__next__()) # 2
num = 0
"""取前五十个值"""
for i in fun:
print(i)
num += 1
if num ==50:
break
"""接着再取五十个值"""
for i in fun:
print(i)
num += 1
if num ==50:
break
3.send()方法:
- 和__next__()方法作用基本一致
- 在获取下一个值的时候给上一个yield传递数据
- 在第一次取值的时候,必须用__next__()
- 如果是函数的最后一个yield是不能接收外部的值的
4.列表推导式和生成器表达式:
- 只需要把列表推导式的[]换成()就变成了生成器表达式
- 生成器表达式和列表推导式相较的优点在于节省内存
"""列表推导式"""
list1 = [i for i in range(1,11)]
print(list1) # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
"""生成器表达式"""
list2 = (i for i in range(1,11))
print(list2) # <generator object <genexpr> at 0x0000017B69C789E0>
print(list2.__next__()) # 1
print(list2.__next__()) # 2
print(list2.__next__()) # 3
"""用sum()和生成器表达式结合计算一系列的和"""
sum = sum(i*2 for i in range(4))
print(sum) #2+4+6 12
三.扩展:
1.列表推导式:
"""循环其他可迭代对象"""
list1 = [i*3 for i in "循环其他可迭代对象"]
print(list1) # ['循循循', '环环环', '其其其', '他他他', '可可可', '迭迭迭', '代代代', '对对对', '象象象']
"""加入判断语句"""
list2 = [i for i in range(11) if i%2 is 0 and i != 0] # 求出十以内的偶数
print(list2) # [2, 4, 6, 8, 10]
"""循环嵌套列表,多个for循环"""
list = [[1,3,"d"],["f","l",9]]
list3 = [j for i in list for j in i]
print(list3) # [1, 3, 'd', 'f', 'l', 9]
"""列表推导式的嵌套"""
list4 = [[i for i in range(j)] for j in range(11) if j % 2 == 0 and j != 0] # 先循环后边 由外到里
print(list4) # [[0, 1], [0, 1, 2, 3], [0, 1, 2, 3, 4, 5], [0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]]
2.字典推导式:
"""利用健来构建value值"""
dict1 = {key:key * 2 for key in "heelo"}
print(dict1) # {'h': 'hh', 'e': 'ee', 'l': 'll', 'o': 'oo'}
"""把原字典的键值调换"""
dict = {'h': 'hh', 'e': 'ee', 'l': 'll', 'o': 'oo'}
dict2 = {dict[key]:key for key in dict}
print(dict2) # {'hh': 'h', 'ee': 'e', 'll': 'l', 'oo': 'o'}
"""把大写换为小写并合并大小写的value值"""
mcase = {'a': 11, 'b': 22, 'A': 33, 'Z': 44}
dict3 = {key.lower() : mcase.get(key.lower(),0)+mcase.get(key.upper(),0) for key in mcase.keys()}
print(dict3) # {'a': 44, 'b': 22, 'z': 44}
3.集合推导式:
- 自带去重功能
set1 = {key:key * 2 for key in "heeloo"}
print(set1) # {'h': 'hh', 'e': 'ee', 'l': 'll', 'o': 'oo'}
set2 = {x**2 for x in {1,-1,2,-2,5}}
print(set2) # {1, 4, 25}