python中的迭代器与生成器
迭代器
有 '__iter__' 方法的就是可迭代对象
列举些可迭代对象:str,list,tuple,dict,set,range,文件句柄
获取一个对象的所有的方法dir();把每个方法以字符串的格式放在一个列表中返回回来
s1 = 'asdfas'
print(dir(s1))
#结果
['__add__', '__class__', '__contains__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__getitem__', '__getnewargs__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__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', 'isascii', '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']
判断所有方法里有没有 __iter__
s1 = 'asdfas'
print('__iter__' in dir(s1))
#True
进入重点(迭代器)
- 迭代器的定义
- 字面意思:更新迭代,器:工具:可更新迭代的工具
- 专业角度:内部含有
__iter__方法并且含有'__next__'方法的对象就是迭代器。 - 可以判断是否是迭代器:
'__iter__'and'__next__'在不在dir(对象)
- 可迭代对象是不能直接for循环取值的,之所以我们能是因为for循环内部自动帮我们转化成迭代器了
可迭代对象可以转化成迭代器
s = 'qwer'
s1 = iter(s)
print('__next__' in dir(s1))
#变量 = iter(要转化的可迭代对象)
#或者这样
s = 'qwer'
s1 = s.__iter__()
print('__next__' in dir(s1))
#(iter()函数就是调用的这个方法)
迭代器是用next()一个一个取值的
s = 'qwer'
s1 = iter(s) #s1 = s.__iter__()
print('__next__' in dir(s1))
print(next(s1)) #s1.__next__()
print(next(s1)) #s1.__next__()
print(next(s1)) #s1.__next__()
print(next(s1)) #s1.__next__()
#少一个next可以,那就少取一个值,多一个不应,就报错(停止迭代的这么一个错误)
'''
True
q
w
e
r
'''
练习:把一个列表转化成迭代器,并用next一个一个取值
li = [11,22,33,44,55,66]
l1 = iter(li)
#print('__next__' in dir(l1))
print(next(l1))
print(next(l1))
print(next(l1))
print(next(l1))
print(next(l1))
print(next(l1))
优点
- 节省内存。
- 惰性机制:next一次就取一个值
- 有一个迭代器模式可以很好的解释上面这两条:迭代是数据处理的基石。扫描内存中放不下的数据集时,我们要找到一种惰性获取数据项的方式,即按需一次获取一个数据项。这就是迭代器模式。
缺点
- 速度慢。以时间换空间
- 不走回头路。
迭代器与可迭代对象的对比
- 可迭代对象是一个私有的方法比较多,操作灵活(比如列表,字典的增删改查,字符串的常用操作方法等),比较直观,存储数据相对少(几百万个对象,8G内存是可以承受的)的一个数据集
- 应用:当你侧重于对于数据可以灵活处理,并且内存空间足够,将数据集设置为可迭代对象是明确的选择。
- 迭代器是一个非常节省内存,可以记录取值位置,可以直接通过循环+next方法取值,但是不直观,操作方法比较单一的数据集。
- 应用:当你的数据量过大,大到足以撑爆你的内存或者你以节省内存为首选因素时,将数据集设置为迭代器是一个不错的选择。(可参考为什么python把文件句柄设置成迭代器)。
while循环模拟for循环机制
利用while循环模拟for循环对可迭代对象进行取值的机制
li = [1,2,3,4,5,6,7]
obj = iter(li)#将可迭代对象转化成迭代器
while 1:
try:
print(next(obj))
except StopIteration:
break
生成器generator
生成器:python社区,生成器与迭代器看成是一种。生成器的本质就是迭代器。唯一的区别:生成器是我们自己用python代码构建的数据结构。迭代器都是提供的,或者转化得来的。
只要有yield就是生成器
- 获取生成器的三种方式:
- 生成器函数
- 生成器表达式
- python内部提供的一些
- 生成器函数获得生成器:yield
- 生成器函数,用函数名加()不执行函数(和函数的区别)
- yield:只要函数中有yield那么它就是生成器函数,而不是函数了
- 生成器函数可以存在多个yield,一个yield对应一个next。yield不会结束生成器函数(return一个函数只能有一个,可以有多个但是执行到第一个就结束了)
- 一个next()对应一个yield,并且把yield的值返回给next()
def func():
print(111)
print(222)
yield 3
a = 1
b = 2
c = a+b
print(c)
yield 4
ret = func()
print(next(ret))
print(next(ret))
'''
111
222
3
3
4
'''
yield from
yield将一个可迭代对象,变成一个生成器
def func():
l1 = [1,2,3,4,5]
yield from l1
#yield from l1 相当于
'''
yield 1
yield 2
yield 3
yield 4
yield 5
'''
#yield from 将l1这个列表变成了迭代器返回
ret = func()
print(next(ret))
print(next(ret))
print(next(ret))
'''
1
2
3
'''
列表推导式
用一行代码构建一个比较复杂有规律的列表。
li = []
for i in range(1,11):
li.append(i)
print(li)
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
l1 = [i for i in range(1,11)]
print(l1)
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
列表推导式:分为两类
-
循环模式:每一个元素都留下来
-
[变量(或加工后的变量) for 变量 in iterable]
-
-
筛选模式:满足条件的留下来,不满足扔了
-
[变量(或加工后的变量) for 变量 in iterable if 条件]#列表中名字有2个e的所有名字留下并大写 names = [['Tom','Billy','Jefferson','Andrew','Wesley','Steven','Joe'], ['Alice','Jill','Ana','Wendy','Jennifer','Sherry','Eva']] li = [i.upper() for i in names[0]+names[1] if i.count('e')==2] li = [j.upper() for i in names for j in i if j.count('e')==2] print(li)
-
生成器表达式
生成器表达式:与列表推导式的写法几乎一模一样。也有循环模式,筛选模式,多层循环构建,写法上只有一个不同:[ ] 换成 ( )
print([i for i in range(1,11)])#列表推导式
#[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print((i for i in range(1,11)))#生成器表达式
#<generator object <genexpr> at 0x000001E2308B2228>
obj = (i for i in range(1,11))
print(next(obj))#1
print(next(obj))#2
print(next(obj))#3
print(next(obj))#4
#或者这样for循环
obj = (i for i in range(1,11))
for i in obj:
print(i)
'''
1
2
3
4
5
6
7
8
9
10
'''

浙公网安备 33010602011771号