Wednesday, October 6, 2010

itertools

itertools 提供了几个能够产生高效的 iterator 的函数。

所谓的 iterator 指实现了 next 方法的对象,这种对象可以使用 for dumb in iter 的方式进行遍历。习惯上对一个对象使用 iter() 方法等价于调用其 __iter__ 方法获得对应的 iterator,而后调用该 iterator 的 next 方法遍历。通常一个 iterator 实现的 __iter__ 方法返回自己。

下面看看 itertools 的 count 方法:
>>> import itertools
>>> c = itertools.count() 
>>> type(c)
<type 'itertools.count'>
>>> dir(c)
['__class__', '__delattr__', '__doc__', '__format__', '__getattribute__', '__hash__', '__init__', '__iter__', '__new__', '__reduce__', '__reduce_ex__', '__repr__', '__setattr__', '__sizeof__', '__str__', '__subclasshook__', 'next']
>>> for i in c:
...     print i
...     if i > 10:
...             break
... 
0
1
2
3
4
5
6
7
8
9
10
11

下面将介绍 itertools 里面其他的一些创建 iterator 的函数。一类和 count 类似,返回的是可以无限迭代下去的:
  • count 返回给定初始值和 step 向后计数的 iterator;
  • cycle 给出循环 iterator;
  • repeat 给出重复某个值的 iterator;
另一类可以看成是对一些 __builtins__ 方法的封装:
  • chain 给出遍历每个参数的每个 iterator 的 iterator
  • compress 有两个参数 a 和 b,返回 a[i] if b[i]
  • dropwhile 两个参数,前面一个条件(functor),后面是遍历的序列,返回去掉序列前面不符合条件的序列的 iterator;
  • groupby 返回的是对 key/data 遍历的 iterator,需要提供 keyfunction 这是前面通过 sort 排序使用的,然后 groupby 就会返回一个 tuple,第一个是 key,第二个是 key 相同的元素列表;
  • ifilter/ifilter_false 和 filter 类似,只是返回的是 iterator 而不是 list;
  • islice 返回类似 slice 操作的 iterator;
  • imap 返回类似 map 操作的 iterator;
  • startmap 和 imap 不同的是,imap 是每个参数一个 list,startmap 是每一组参数一个;
  • tee 可以将一个 iterator 变成 n 个独立的 iterator,这样某些问题里面可以分开到多线程里面处理; tee 过的 iterator 最好不要用在别处;
  • takewhile 和 dropwhile 类似,但是仅仅取条件成功的元素;
  • izip 和 zip 类似的 iterator;izip_longest 允许设置 fillvalue 用于补齐;
  • product 用于产生 Decartes 积;
  • permutations 用于产生置换;
  • combinations 产生组合;combination_with_replacement 带重复的组合;

需要说明的是 python 比较奇怪的产生 iterator 的方式是返回使用 yield 关键字,这种对象/函数一般称为 generator,利用 generator 可以很容易写出 iterator,而不打扰遍历的逻辑。比如文档中给出的 chain 函数的等价写法
def chain(*iterables): 
    # chain(’ABC’, ’DEF’) --> A B C D E F 
    for it in iterables:
        for element in it: 
            yield element
逻辑上我们就是这样遍历 chain 的所有参数,但是如果要写成一个 iterator 会比较麻烦,需要记录遍历到哪个参数了,它的 iteraotor 是谁,iteration 结束后跳到下一个参数;而 yield 的写法就很直观。

另外 iteration 结束 iterator 需要 raise StopIteration 的异常;如果使用 yield 则没有必要手工写这个异常。

No comments:

Post a Comment