可迭代对象:可以直接作用于for循环的对象,称为可迭代对象。
可以直接用for循环的数据类型有:
- 集合数据类型,字符串,列表,元祖,字典,集合等。(都是Iterable对象,但不是Iterator,但是可以通过iter()变成Iterator对象)
- generator,包括生成器和带yield的generator function。 (调用返回一个Iterator)
可迭代对象都有一个__iter__方法
例如:
>>> dir([]) ['__add__', '__class__', '__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']
判断一个对象是否是Iterable可迭代对象可以使用 isinstance() 方法
from collections import Iterable >>> isinstance([],Iterable) True >>> isinstance({},Iterable) True >>> isinstance((x for x in range(5)),Iterable) True
迭代器 Iterator:可以被__next__() 函数调用并不断返回下一个值的对象
可以使用isinstance()判断一个对象是否是Iterator
>>> from collections import Iterator >>> it=(x for x in range(1,3)) >>> it <generator object <genexpr> at 0x7fed717c9db0> >>> isinstance(it,Iterator) True >>> isinstance([],Iterator) False
迭代器特点:
- 不能随机访问集合中的某个值,只能从头到尾依次访问
- 迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。只往前进不能后退
- 仅仅在迭代到某个元素时才会计算它,不需要事先准备所有的元素。便于循环比较大的数据集合,节省内存。类似cat,more命令。
可迭代对象不一定是迭代器,迭代器一定是可迭代对象。
迭代器除了有__iter__方法,还有__next__方法
>>> it = iter(['a','b','c']) >>> it <list_iterator object at 0x7fd5bb4f76a0> >>> dir(it) ['__class__', '__delattr__', '__dir__', '__doc__', '__eq__', '__format__', '__ge__', '__getattribute__', '__gt__', '__hash__', '__init__', '__init_subclass__', '__iter__', '__le__', '__length_hint__', '__lt__', '__ne__', '__new__', '__next__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__']
可以通过iter()将Iterable变成Iterator
# a.__next__()输出迭代器的下一个元素 等同于2.7里next(a)
>>> b= ('lily','jack','kang')
>>> a = iter(b)
>>> a
<tuple_iterator object at 0x7fed717cbf98>
>>> next(a) #2.7写法 ,3里面用__next__()
'lily'
>>> a.__next__()
'jack'
>>> a.__next__() ## 已迭代完所有元素,再执行会报错StopIteration
'kang'
>>> next(a)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
StopIteration
# 迭代器也可以用for语句遍历
a = iter(('lily','jack','kang'))
for i in a:
print(i,end=' ')
生成器:一个函数调用返回一个迭代器,这个函数就是生成器(generator)
- 生成器是可以迭代的 但是只可以读取一次
生成器表达式:
>>> ge = (x for x in range(5)) #生成器使用 () 区别于列表推导式[] >>> ge <generator object <genexpr> at 0x7fe0b4417048> >>> ge.__next__() 0 >>> ge.__next__() #可以通过__next__()方法不断返回下一个 1 >>> for i in ge: #也可以用for循环 ... print(i) ... 2 3 4
生成器函数
普通函数与生成器函数的区别:
普通函数调用直接返回一个结果,generator函数调用返回一个迭代器
# 遇到yield语句就返回,再次执行时从上次返回的yield语句处继续执行
def foo(num): while num > 0: num -= 1 yield num #return跳出循环后不能再返回,但是yield跳出此次循环还可以继续下一次 print('减少1') f = foo(3) # 此时没有真正执行函数,只是把f变成一个迭代器 print(f.__next__()) print('-----') print(f.__next__()) print(f.__next__()) -------------> 2 ----- 减少1 1 减少1 0
def odd(): print('step1') yield 1 #运行完yield1停止 print('step2') #下一次执行从yield1后面开始执行 yield 3 print('step3') yield 5 o=odd() print(next(o)) -------> step1 1 print(next(o)) --------> step2 2 ........................................................................ def gen(func): for i in range(func): yield i for x in gen(5): print(x,end=' ') ----> 0 1 2 3 4
#!/usr/bin/python3 def func(): print('----start-------') a,b=0,1 for i in range(4): print('1') yield b print('2') a,b=b,a+b print('3') print('------stop-----') f=func() print(next(f)) print(next(f)) print(next(f)) print(next(f)) --------------------输出-》 ----start------- #print('1') #yeild b 返回1 第一次迭代完成 #print('2') 下一次迭代从yeild b 后面开始 #print('3') #print('1') #yeild b 第二次迭代完成 3 2 #yeild b 第三次迭代完成 3 3 #yeild b 第四次迭代完成