python 中的 for 迭代

Iterator的基本使用方法

    我们知道,常用的iterator使用方法有直接的for循环。而从前面的文章里也看到,在某些情况下,因为iterator里面有定义了__next__()方法,我们可以调用next()方法来访问它。

    比如说我们有一个文件test.txt,我们需要读出来里面的内容。一个最常用的方法如下:

Python代码  收藏代码
  1. with open('test.txt') as f:  
  2. ...     for line in f:  
  3. ...         print(line, end='')  

  我们也可以采用对应的next()方法,对应实现的代码如下:

Python代码  收藏代码
  1. with open('test.txt') as f:  
  2. ...     try:  
  3. ...         while True:  
  4. ...             line = next(f)  
  5. ...             print(line, end='')  
  6. ...     except StopIteration:  
  7. ...         pass  

    我们知道,整因为iterator内部的实现是通过StopIteration这个异常来保证运行的结束,所以这里才需要捕捉这个异常来作为访问结束的退出。和前面的方法比起来,这个显得稍微臃肿了一点。当然,我们可以对这些代码稍微改进一点,毕竟只是一个判断迭代器是否走完,用异常显得太笨重。改进后的代码如下:

Python代码  收藏代码
  1. with open('test.txt') as f:  
  2.         while True:  
  3.             line = next(f, None)  
  4.             if line is None:  
  5.                 break  
  6.             print(line, end='')  

    这里的一个区别就是next()方法多带了一个参数None, 这里表示如果后面读取不到内容了,则返回None,这样我们就不用再去通过捕捉异常的方式来判断,只要判断一下读取到的内容是否为None就可以了。

    这几种方式的比较,第一种显然要简单一些。只是在某些情况下如果我们没法用for循环去访问迭代器的时候,可以考虑用后面这种方式。

 

反向移动Iterator

     在通常情况下,我们迭代器都是从头到尾的去遍历元素集合,但是在某些特殊的情况下,比如说我们需要从集合的末位遍历到开头,那该怎么来使用iterator呢?一个简单的办法就是使用reversed()方法。最常用的方式在于对一个list操作:

Python代码  收藏代码
  1. >>> a = [1234]  
  2. >>> for x in reversed(a):  
  3. ...     print(x)  
  4. ...   
  5. 4  
  6. 3  
  7. 2  
  8. 1  

    在前面访问文件的示例中,如果我们也希望达到这样的效果,则需要将文件内容先读进内存,然后按照相反的顺序输出,这种实现的方式如下:

Python代码  收藏代码
  1. f = open('test.txt')  
  2. for line in reversed(list(f)):  
  3.     print(line, end='')  

    这种方式有一个潜在的问题,就是对于比较小的文件是可行的,对于比较大的文件,如果不可能将所有内容都装载到内存中的话,这种方法就不可行了。需要通过f.seek()先找到文件的末位,然后再倒过来一步步的往前读。

    我们知道,对于一个对象来说,如果它实现了 __iter__方法,相当于实现了一个迭代器的返回定义方法。所以我们可以通过iter()来取得这个对象的迭代器。然后我们再通过循环来遍历它。对于反向遍历,我们也可以定义类似的方法实现:

Python代码  收藏代码
  1. class Countdown:  
  2.     def __init__(self, start):  
  3.         self.start = start  
  4.   
  5.     def __iter__(self):  
  6.         n = self.start  
  7.         while n > 0:  
  8.             yield n  
  9.             n -= 1  
  10.   
  11.     def __reversed__(self):  
  12.         n = 1  
  13.         while n <= self.start:  
  14.             yield n  
  15.             n += 1  

    这里相当于定义了两个迭代器,一个是正向的,一个是反向的。我们可以这样来使用它们:

Python代码  收藏代码
  1. >>> for n in iter(c):  
  2. ...     print(n)  
  3. ...   
  4. 10  
  5. 9  
  6. 8  
  7. 7  
  8. 6  
  9. 5  
  10. 4  
  11. 3  
  12. 2  
  13. 1  
  14. >>> for n in reversed(c):  
  15. ...     print(n)  
  16. ...   
  17. 1  
  18. 2  
  19. 3  
  20. 4  
  21. 5  
  22. 6  
  23. 7  
  24. 8  
  25. 9  
  26. 10  

 

Iterator数据切片

    有的时候我们希望取迭代器数据中间的一部分。一种典型的思路就是我用一个计数器,专门计算取到那个范围的再统一返回。实际上这里有一种比较简单的手法。就是使用itertools.islice()方法。以前面我们读取文件的代码为例:

Python代码  收藏代码
  1. >>> with open('test.txt') as f:  
  2. ...     import itertools  
  3. ...     for x in itertools.islice(f, 24):  
  4. ...         print(x)  
  5. ...   
  6. ghi  
  7.   
  8. jkl  

    这里实际返回的是第3行和第4行的内容。实际上itertools.islice()方法通过指定的参数(2, 4)确定了取的值范围为第3,4行。然后通过丢弃前面的行,直到进入到我们所要求的数据范围。这样就省略了很多我们自己来写一个计数器跟踪它们的代码。islice()方法可以起到一个很好的数据范围过滤效果。如果我们设定itertools.islice(f, 2, None),则相当于取数组f[2:]的效果。

 

Iterator内容过滤

    我们在遍历一些集合的时候,希望过滤掉一部分元素。这个时候,一个典型的方法就是我们所想到的list comprehension,比如说,我们要输出一个文件的内容,但是要跳过里面所有加了#号的注释部分。我们可以这样来做:

Python代码  收藏代码
  1. >>> with open('test.txt') as f:  
  2. ...     lines = (line for line in f if not line.startswith('#'))  
  3. ...     for line in lines:  
  4. ...         print(line, end='')  

    如果有的时候我们只是为了跳过文件开头的那部分注释呢?还有一个更加简单的办法,就是利用itertools里的dropwhile方法。这种用法如下:

Python代码  收藏代码
  1. >>> from itertools import dropwhile  
  2. >>> with open('test.txt') as f:  
  3. ...     for line in dropwhile(lambda line: line.startswith('#'), f):  
  4. ...         print(line, end=''
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值