自学python过程中会遗漏一些东西,当初看书的时候碰到这些都跳过了,在一次面试中被问到了生成器,才意识到它在使用中的重要性,然后重新翻回去看了书并总结如下。
1、迭代器(Iterator)
在Python中的for循环使用的就是迭代器的机制,与C语言的循环有所不同。由于使用了迭代器,for循环除了支持常见的序列(元组、列表)外,还支持字典和文件对象。对于任何的可迭代对象都有一个iter方法,使用iter之后函数返回的就是一个迭代器对象,得到迭代器对象后就可以不断使用next方法得到他的下一个值,直到所有值都取完之后返回StopIteration异常。for循环内部实现就是这样的一个过程,并且它自动处理了StopIteration异常,使用更加方便。
dic = {'a':1, 'b':2, 'c':3}
iter_test = iter(dic)
print(next(iter_test)) //print(iter_test.__next__())
print(next(iter_test)) //print(iter_test.__next__())
print(next(iter_test)) //print(iter_test.__next__())
print(next(iter_test)) //print(iter_test.__next__())
a
b
c
Traceback (most recent call last):
File "xxx.py", line 7, in <module>
print(next(iter_test))
StopIteration
上面一个很简单的例子,字典为可迭代对象,使用iter返回迭代器对象后不断调用next得到下一个值(使用next或者__next__都可以)。注意在遍历完字典后会抛出StopIteration异常,如果自己写的话要注意使用try/except语句进行处理。如果仅仅为了遍历可以直接对字典进行for循环,可以减少异常处理流程。不过迭代器在使用中只能不断返回下一个值,不能得到前面的值。
2、生成器(generator)
从使用上看生成器是一种可迭代对象同时也是一种迭代器。对于生成器可以直接使用next或者__next__方法来得到下一个值。生成器主要是用于产生一个序列可用于迭代处理的一种实现方法。如果数据量很大的话,使用列表之类的对象处理需要一下把所有数据都存储下来,而生成器在每次调用的时候返回一个值,同时记录执行的情况在下次调用的时候再次返回下一个值,这样的话就不会占用很大的资源从而提高执行效率。这个也许是生成器的一个合适的定义。其实现方法主要有生成器表达式和yield关键字:
def gene():
yield 0
yield 1
yield 2
yield 3
a = gene()
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
0
1
2
3
Traceback (most recent call last):
File "xxx.py", line 13, in <module>
print(next(a))
StopIteration
从这里看的话生成器跟迭代器的使用是一致的,也会抛出异常。如果使用dir(gene)来看他的方法的话同时有__iter__方法和__next__方法,可以说明生成器也是可迭代对象,尝试用iter(gene)也不会出现错误。下面是生成器表达式的示例,生成器表达式的写法和列表解析的方法类似,只是由方括号改为圆括号:
a = (i for i in range(4))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
print(next(a))
0
1
2
3
Traceback (most recent call last):
File "xxx.py", line 7, in <module>
print(next(a))
StopIteration
3、在python内部实现中有很多函数的输入都是可迭代对象(iterable),而生成器也属于一种可迭代对象。python很多内建函如all、any、max、sum、enumerate等,其输入参数都是可迭代对象,因此生成器也可以作为输入参数使用。
a = (i for i in range(4))
print(sum(a))
6
本文仅仅从使用的角度进行总结,对于底层原理的实现暂时还没有深入研究。
来源:CSDN
作者:争xx鸣
链接:https://blog.csdn.net/xxx88qqq/article/details/82051842