文章目录
前言
在一种语言中有些语法元素属于高级语法元素,有着一些有趣或者难以理解的特性,其中最常见的是迭代器、生成器、装饰器、上下文管理器本文将介绍迭代器、生成器、上下文管理器。
一、迭代器
可迭代对象
内部持有__iter__()方法的对象。
迭代器
迭代是Python最强大的功能之一,是访问集合元素的一种方式。迭代器是一个可以记住遍历的位置的对象。任何实现了__iter__和__next__()方法即迭代器协议的对象都是迭代器。__iter__返回迭代器自身【对应iter()方法】,__next__返回容器中的下一个值【next(generator),只能依次正序生成,生成数据不能再次生成。所有生成器不能超过迭代次数
】。迭代器对象从集合的第一个元素开始访问,直到所有的元素被访问完结束。迭代器只能往前不会后退。字符串,列表或元组对象都可用于创建迭代器。
使用
迭代器的自动访问
通过上面我们可以知道next()可以返回迭代器的下一个值,但有时候我们需要它自动访问。我们可以用for循环。
with open("exhibitionism.txt") as f:
try:
while True:
line=next(f)
print(line,end=' ')
except StopIteration:
pass
#----等价于
with open("exhibitionism.txt") as f:
while True:
line=next(f,None)
if line is None:
break
print(line,end='')
注:使用next函数可以了解底层迭代器精细控制的情况。
for循环内部三件事:
- 调用可迭代对象的iter方法返回一个迭代器对象。
- 不断调用迭代器对象的next方法。
- 处理stopIteration
委托迭代
让自己的新容器对象【内部包含持有一个可迭代对象】能够完成迭代操作。一般来说我们要定义一个__iter__()方法,将迭代请求委托到对象内部持有的容器上。
class Node:
def __init__(self,value):
self._value=value
self._children=[]
def __repr__(self):
return 'Node({!r})'.format(self._value)
def add_child(self,node):
self._children.append(node)
print(self._children)
def __iter__(self):
return iter(self._children)
root=Node(0)
child1=Node(1)
child2=Node(2)
root.add_child(child1)
root.add_child(child2)
for ch in root:
print(ch)
'''
结果:
[Node(1)]
[Node(1), Node(2)]
Node(1)
Node(2)
'''
对迭代器做切片操作
切片我们不陌生,普通的切片操作不能对迭代器产生的数据做切片处理,itertools.islice()函数是完美的选择。
def Cutdown(n):
while n>0:
yield n
n-=1
#Cutdown(6)[1:2]#'generator' object is not subscriptable
import itertools
s=itertools.islice(Cutdown(6),1,3)#<itertools.islice object at 0x0000017D0696B7C0>
注:islice()函数产生的数据和迭代器一样,只能访问一次,访问多次还需要转换成列表。
跳过可迭代对象中的一部分元素
我们已经知道了普通切片操作无法对生成器使用,如果我需要跳过一部分元素,那应该如何操作呢?需求简单如跳过前N个元素可以使用islice(iter,N,None)的方法。需求复杂你可能会考虑过滤函数filter,其实我们还可以使用itertools.dropwhile(Lf,iterable)【函数参数前者为过滤函数,后者为可迭代对象】。
import itertools
def Cutdown(n):
while n>0:
yield str<