写在前面:
迭代:类似对可迭代对象执行 for…in… 这样操作的过程叫做迭代
像 Python 的基础类型 list、dict、str 都属性可迭代对象,可以这样来判断一个对象是不是可迭代对象:
from collections.abc import Iterable
if __name__ == "__main__":
print(isinstance("dolphin", Iterable))
print(isinstance([1, 2, 3], Iterable))
print(isinstance({'name': 'dolphin'}, Iterable))
输出结果:
True
True
True
那除了这些基础对象类型之外,我们可以自已定义一个可迭代对象吗?
当然是可以的,可迭代对象的本质是开检查这个对象有没有实现 iter 方法。
一个对象是否可迭代表现在其是否有实现__iter__方法。所以可以这样来定义一个可迭代对象
from collections.abc import Iterable
class MyList():
"""
这里只是为展示如何定义可迭代对象,只有简单的这种没有任何意义的
"""
def __init__(self):
pass
# 实现 __iter__ 方法
def __iter__(self):
pass
if __name__ == "__main__":
print(isinstance(MyList(), Iterable))
输出结果:
True
如上示例中定义的 MyList 类,虽然使用 isinstance 来验证时已经是可迭代对象,但是因为没有实现 iter 方法,在真正迭代的时候就会出问题。那应该怎么实现 iter 方法呢?
iter 方法需要返回一个迭代器来供进行迭代操作时使用!
迭代器是一个可以在迭代过程中记住当前迭代位置的对象。 它从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能前进不会后退。
迭代的过程是对迭代器不断的使用 next 方法。
if __name__ == "__main__":
iterable_obj = [1, 2, 3, 4, 5, 6]
# 可以通过 iter 方法获取到可迭代对象的迭代器
iterable_obj_iter = iter(iterable_obj)
# 使用 next 获取迭代器元素
iterable_obj_0 = next(iterable_obj_iter)
iterable_obj_1 = next(iterable_obj_iter)
iterable_obj_2 = next(iterable_obj_iter)
print(iterable_obj_0)
print(iterable_obj_1)
print(iterable_obj_2)
输出结果:
1
2
3
for…in… 的实质就是不断的调用__next__方法。那这是怎么使用迭代器,到底怎么定义迭代器呢?
当要定义一个迭代器时,只要实现__next__方法他就是一个迭代器了。(但是关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。)
from collections.abc import Iterator
class MyIterator():
def __next__(self):
pass
# 迭代器自身也是可迭代的,返回它自己
def __iter__(self):
return self
if __name__ == "__main__":
my_iterator = MyIterator()
print(isinstance(my_iterator, Iterator))
输出结果:
True
千万要注意: 迭代器是有状态的,在使用它的时候只可以迭代一次,尽量不要讲迭代器作为函数参数,会引发一些不可知的错误。
利用迭代器,我们可以在每次迭代获取数据(通过next()方法)时按照特定的规律进行生成。但是在实现一个迭代器时,关于当前迭代到的状态需要我们自己记录,进而才能根据当前状态生成下一个数据。为了达到记录当前状态,并配合next()函数进行迭代使用,我们可以采用更简便的语法,即生成器(generator)。生成器是一种特殊的迭代器。
把列表生成器的 [] 替换为 () 你将得到一个生成器。
通常在使用列表生成器的时候是这样的
if __name__ == "__main__":
my_list = [x for x in range(10)]
print(type(my_list))
输出结果:
但是如果吧列表生成式的 [] 改成 () 将会得到一个生成器。
if __name__ == "__main__":
# 注意这里 将 [] 换成了 ()
my_list = (x for x in range(10))
print(type(my_list))
输出结果:
def fib(n):
current = 0
num1, num2 = 0, 1
while current < n:
num = num1
num1, num2 = num2, num1 + num2
current += 1
yield num
return 'done'
if __name__ == "__main__":
f = fib(6)
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
print(next(f))
# 超出
print(next(f))
输出结果:
0
1
1
2
3
5
Traceback (most recent call last):
File “test.py”, line 24, in
print(next(f))
StopIteration: done
注意: 当迭代生成器时,如果生成器中没有数据了,会抛出 StopIteration 异常,必须要处理它的哟~