概述
Iterator的基本使用方法
我们知道,常用的iterator使用方法有直接的for循环。而从前面的文章里也看到,在某些情况下,因为iterator里面有定义了__next__()方法,我们可以调用next()方法来访问它。
比如说我们有一个文件test.txt,我们需要读出来里面的内容。一个最常用的方法如下:
- with open('test.txt') as f:
- ... for line in f:
- ... print(line, end='')
我们也可以采用对应的next()方法,对应实现的代码如下:
- with open('test.txt') as f:
- ... try:
- ... while True:
- ... line = next(f)
- ... print(line, end='')
- ... except StopIteration:
- ... pass
我们知道,整因为iterator内部的实现是通过StopIteration这个异常来保证运行的结束,所以这里才需要捕捉这个异常来作为访问结束的退出。和前面的方法比起来,这个显得稍微臃肿了一点。当然,我们可以对这些代码稍微改进一点,毕竟只是一个判断迭代器是否走完,用异常显得太笨重。改进后的代码如下:
- with open('test.txt') as f:
- while True:
- line = next(f, None)
- if line is None:
- break
- print(line, end='')
这里的一个区别就是next()方法多带了一个参数None, 这里表示如果后面读取不到内容了,则返回None,这样我们就不用再去通过捕捉异常的方式来判断,只要判断一下读取到的内容是否为None就可以了。
这几种方式的比较,第一种显然要简单一些。只是在某些情况下如果我们没法用for循环去访问迭代器的时候,可以考虑用后面这种方式。
反向移动Iterator
在通常情况下,我们迭代器都是从头到尾的去遍历元素集合,但是在某些特殊的情况下,比如说我们需要从集合的末位遍历到开头,那该怎么来使用iterator呢?一个简单的办法就是使用reversed()方法。最常用的方式在于对一个list操作:
- >>> a = [1, 2, 3, 4]
- >>> for x in reversed(a):
- ... print(x)
- ...
- 4
- 3
- 2
- 1
在前面访问文件的示例中,如果我们也希望达到这样的效果,则需要将文件内容先读进内存,然后按照相反的顺序输出,这种实现的方式如下:
- f = open('test.txt')
- for line in reversed(list(f)):
- print(line, end='')
这种方式有一个潜在的问题,就是对于比较小的文件是可行的,对于比较大的文件,如果不可能将所有内容都装载到内存中的话,这种方法就不可行了。需要通过f.seek()先找到文件的末位,然后再倒过来一步步的往前读。
我们知道,对于一个对象来说,如果它实现了 __iter__方法,相当于实现了一个迭代器的返回定义方法。所以我们可以通过iter()来取得这个对象的迭代器。然后我们再通过循环来遍历它。对于反向遍历,我们也可以定义类似的方法实现:
- class Countdown:
- def __init__(self, start):
- self.start = start
- def __iter__(self):
- n = self.start
- while n > 0:
- yield n
- n -= 1
- def __reversed__(self):
- n = 1
- while n <= self.start:
- yield n
- n += 1
这里相当于定义了两个迭代器,一个是正向的,一个是反向的。我们可以这样来使用它们:
- >>> for n in iter(c):
- ... print(n)
- ...
- 10
- 9
- 8
- 7
- 6
- 5
- 4
- 3
- 2
- 1
- >>> for n in reversed(c):
- ... print(n)
- ...
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
Iterator数据切片
有的时候我们希望取迭代器数据中间的一部分。一种典型的思路就是我用一个计数器,专门计算取到那个范围的再统一返回。实际上这里有一种比较简单的手法。就是使用itertools.islice()方法。以前面我们读取文件的代码为例:
- >>> with open('test.txt') as f:
- ... import itertools
- ... for x in itertools.islice(f, 2, 4):
- ... print(x)
- ...
- ghi
- jkl
这里实际返回的是第3行和第4行的内容。实际上itertools.islice()方法通过指定的参数(2, 4)确定了取的值范围为第3,4行。然后通过丢弃前面的行,直到进入到我们所要求的数据范围。这样就省略了很多我们自己来写一个计数器跟踪它们的代码。islice()方法可以起到一个很好的数据范围过滤效果。如果我们设定itertools.islice(f, 2, None),则相当于取数组f[2:]的效果。
Iterator内容过滤
我们在遍历一些集合的时候,希望过滤掉一部分元素。这个时候,一个典型的方法就是我们所想到的list comprehension,比如说,我们要输出一个文件的内容,但是要跳过里面所有加了#号的注释部分。我们可以这样来做:
- >>> with open('test.txt') as f:
- ... lines = (line for line in f if not line.startswith('#'))
- ... for line in lines:
- ... print(line, end='')
如果有的时候我们只是为了跳过文件开头的那部分注释呢?还有一个更加简单的办法,就是利用itertools里的dropwhile方法。这种用法如下:
- >>> from itertools import dropwhile
- >>> with open('test.txt') as f:
- ... for line in dropwhile(lambda line: line.startswith('#'), f):
- ... print(line, end='')
最后
以上就是粗暴时光为你收集整理的python 中的 for 迭代的全部内容,希望文章能够帮你解决python 中的 for 迭代所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复