可迭代对象
概念
一个对象(在Python里面一切都是对象)只要实现了只要实现了__iter__()方法,那么这个对象就是可迭代对象
常见的可迭代对象
- 集合或序列类型(如list、tuple、set、dict、str)或文件对象
- 在类中定义了__iter__()方法的对象,可以被认为是 Iterable对象,但自定义的可迭代对象要能在for循环中正确使用,就需要保证__iter__()实现必须是正确的
- 在类中实现了如果只实现__getitem__()的对象可以通过iter()函数转化成迭代器但其本身不是可迭代对象。所以当一个对象能够在for循环中运行,但不一定是Iterable对象。
针对第一点可以使用print(isinstance([], Iterable)) 进行校验,返回True则是可迭代对象。
关于第二点我们可以通过print(hasattr([], "__iter__"))返回True知道内部实现了__iter__方法,但是这里我们需要注意的是要想被for循环遍历,能够被内置的iter()函数调用并转化成Iterator对象(如下代码所示)
from collections import Iterable
class IterObj:
def __iter__(self):
return self
print(isinstance([], Iterable))
it = IterObj()
print(iter(it))
关于 第四点可以根据如下实例理解
from collections import Iterable, Iterator, Generator
class IterObj:
def __init__(self):
self.a = [3, 5, 7, 11, 13, 17, 19]
def __getitem__(self, i):
return self.a[i]
it = IterObj()
print(isinstance(it, Iterable)) # false
print(hasattr(it, "__iter__")) # false
print(isinstance(iter(it), Iterable)) # true
for i in it:
print(i) # 将打印出3、5、7、11、13、17、19
迭代器
概念
迭代器对象要求支持迭代器协议的对象,在Python中,支持迭代器协议就是实现对象的__iter__()和next()方法。其中__iter__()方法返回迭代器对象本身;next()方法返回容器的下一个元素,在结尾时引发StopIteration异常。简单来说:一个对象实现了__iter__()和__next__()方法,那么它就是一个迭代器对象。
实例
class IterObj:
def __init__(self, n):
self.a = n
self.n = len(self.a)
self.i = 0
def __iter__(self):
return iter(self.a)
def __next__(self):
while self.i < self.n:
v = self.a[self.i]
self.i += 1
return v
else:
self.i = 0
raise StopIteration()
t = IterObj([3, 5, 7, 11, 13, 17, 19])
# 可以通过for遍历
print([ i for i in t])
# 也可以通过next(因为遍历到没有数据时候,抛出异常所以需要捕捉下)
while True:
try:
print(t.__next__())
except:
break
区分iterable,iterator与itertion
-
itertion
: 就是迭代
,一个接一个(one after another),是一个通用的概念,比如一个循环遍历某个数组。 -
iterable
: 这个是可迭代对象
,属于python的名词,范围也很广,可重复迭代,满足如下其中之一的都是iterable
:-
可以
for
循环:for i in iterable
-
可以按
index
索引的对象,也就是定义了__getitem__
方法,比如list,str
; -
定义了
__iter__
方法。可以随意返回。 -
可以调用
iter(obj)
的对象,并且返回一个iterator
-
-
iterator
:迭代器对象
,也属于python的名词,只能迭代一次。需要满足如下的迭代器协议
-
定义了
__iter__
方法,但是必须返回自身 -
定义了
next
方法,在python3.x是__next__
。用来返回下一个值,并且当没有数据了,抛出StopIteration
-
可以保持当前的状态
-
优缺点
迭代器优点:
- 提供了一种通用不依赖索引的迭代取值方式
- 同一时刻在内存中只存在一个值,更节省内存
迭代器缺点:
- 取值不如按照索引的方式灵活,不能取指定的某一个值,只能往后取,不能往前去
- 无法预测迭代器的长度
生成器
概念
生成器就是一种自定义的迭代器,本质为迭代器,但凡函数内包含yield关键字,调用函数不会执行函数体代码,会得到一个返回值,该返回值就是生成器对象。在廖雪峰教程中解释为:在Python中,这种一边循环一边计算的机制,称为生成器(Generator)
注意: 生成器既是可迭代的也是迭代器
定义生成器有两种方式:
- 列表生成器
- 使用
yield
定义生成器函数 (yield
是一个语法糖,内部实现了迭代器协议,同时保持状态可以挂起)
列表生成器
from collections import *
g = (x for x in range(3)) # 0~18的偶数生成器
print(isinstance(g, Iterable)) # true
print(isinstance(g, Iterator)) # true
print(isinstance(g, Generator)) # true
print(hasattr(g, "__iter__")) # true
print(hasattr(g, "__next__")) # true
print(next(g)) # 0
print(next(g)) # 1
print(next(g)) # 2
使用yield
定义生成器函数
def gen():
for i in range(10):
yield i
# 检索数据,开始执行
a = gen()
print(list(a))
# 调用gen()并没有真实执行函数,而是只是返回了一个生成器对象
# 执行第一次a.next()时,才真正执行函数,执行到yield一个返回值,然后就会挂起,
# 保持当前的名字空间等状态。然后等待下一次的调用,从yield的下一行继续执行。
a = gen()
print(a.__next__())
这里yield
的作用就相当于return
,这个函数就是顺序地返回[0,9]
的之间的自然数,可以通过next()
或使用for
循环来遍历。当程序遇到yield
关键字时,这个生成器函数就返回了,直到再次执行了next()
函数,它就会从上次函数返回的执行点继续执行,即yield
退出时保存了函数执行的位置、变量等信息,再次执行时,就从这个yield
退出的地方继续往下执行。
迭代器和生成器的区别
生成器能做到迭代器能做的所有事,而且因为自动创建了 iter()和 next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。
参考链接
python的迭代器为什么一定要实现__iter__方法?
Python:range 对象并不是迭代器(英文)
Python:range 对象并不是迭代器
python迭代器与生成器小结
python迭代器和for循环区别
Python迭代器,生成器--精华中的精华