Python iteration

Python iteration

Python 的 迭代协议 (iteration protocol):

请注意 术语 iterator 和 术语 iterable 的区别:

所谓 iterable, 顾名思义,就是可迭代的。什么对象是可迭代的 ? 就是支持 iter 函数调用 (参考 python built-in function : iter)的对象,执行该函数调用,会返回一个 iterator 迭代器对象 (object)。

iterator 迭代器对象 (object),一定包含 __next__ 方法,或者说支持 next 函数调用 (同样参考 python built-in function: next) ,可以递进到下一个值 (这里不知道怎么翻译比较好 , advance to a next result),并在结果序列的末尾抛出 StopIteration 异常,那么这个对象是 迭代器 (iterator)

1. for 的背后

先看两个例子,首先我们知道 list object 是 iterable 的,因为它有 __iter__ 方法 (用前面提到的 dir 方法可以确认),或者说 它可以作为内建函数 iter() 的参数,返回的对象是 iterator

然后,我们也都熟悉 list object 是可以用 for 循环的

但是 !!! , 如果我们直接用 iterator 用于 for 循环,发现结果是相同 !!!!!

说明 for 循环同时支持 iterable object 和 iterator object

When the for loop begins, it first obtains an iterator from the iterable object by passing it to the iter built-in function; the object returned by iter in turn has the required next method.

也就是说,for 循环遍历是 iterable object, 它会在最开始多加一步,调用 iter 获得它的 iterator object, 后面的过程和直接使用 iterator object 是相同的,我们调用 next 不断获得下一个值

  1. The iterable object for which you request iteration, whose __iter__ is run by iter
  2. The iterator object returned by the iterable that actually produces values during the iteration, whose __next__ is run by next and raises StopIteration when finished producing results.

通常情况下,iterator object 是临时的,仅被迭代工具 (iteration tool) 内部使用

下图展示了 Python 的 Iteration Protocol

注:

  1. 一些 Object 既是 iteration context tool (they iterate), 又是 iterable object (their results are iterable),包括 generator, map, zip
  2. 还有一些 object 既是 iterable , 又是 iterator,比如
    open() 的返回 :

2. iterable / iterator的例子

2.1 Dictionary

dictionary 的键值 (keys) 是 iterable, 一般用于 for 循环

在最新的 Python 版本中, dictionaries 也成了 iterable, iter() 返回它的键值 (key) 的 iterator

因此我们可以在 for 循环中直接使用 dictionary 本身

2.2 open() / os.popen()

open() 返回的既是 iterator, 又是 iterable

os.popen() 执行 shell command 并将结果返回,返回的是 iterator,

我们发现要给奇怪的现象, popen() 返回的对象支持 __next__() 方法,但不支持内建函数 next(P) 。但是我们要知道 os.popen() 返回的对象更类似 iterable , 我们可以先获取它的迭代器 (iterator),然后使用 next()

2.3 range()

range() 返回的 object 是 iterable, 不是 iterator。

请注意我们的最后一行测试,如果在执行两次 next() 后,再执行 list(I) ,返回的是 [2, 3, 4] ,这符合前面的 iteration protocol,因为协议内部就是调用 __next__() 方法,而我们之前已经手动执行了两次,自然要在这之后了,而不是从头开始。

2.4 enumerate()

enumerate() 同样也是返回的 iterable

2.5 map, zip , filter

range 类似,map, zip , filter 同样也是 Python3 支持的内建函数,返回的既是 iterable , 也是 iterator。它们的 iter 返回的就是它们本身

特性:

为了节省内存空间,它们都不会在内存中一次性存储所有计算结果。 这就导致一个有趣的现象,每个函数调用 __iter__() 返回的 iterator 其实只有一个,并且指向结果中最新的位置

After you step through their results once, they are exhausted (疲劳). In other words, you can’y have multiple iterators on their results that maintain different positions in those results.

也就是说,每个 map, zip, filter 返回 object 的迭代器有且只有一个,用完就没有了,这是对节省内存资源和计算资源的的优势的妥协。如果想多次使用计算结果,只能把结果存储在 list 中,但这样就失去之前的优势了。鱼和熊掌不可兼得啊 !!

这就是 range 的 multiple iterator 和 map , zip ,filter 的 single active iterator 的不同, 在 for 循环中请注意这一点,

Multiple iterators are usually supported by returning new objects for the iter call; a single iterator generally means an object returns itself.

方法:

  • 重新获得一个 map, zip , filter 返回的 object
  • list, tuple 存储结果

最后是 filter ,It returns items in an iterable for which a pass-in function returns True

其实 filter() 也可以被 列表生成式语义模拟

3. List comprehension – 列表生成式

列表生成式的效果和 map 类似,但 map 要求的是 函数,而 list comprehension 要求任意表达式

其实, lists , set, dictionaries, and generators can all be built with comprehension

both types of objects are considered iterable because they support the iteration protocol – they respond to the iter call with an object that advances in response to next calls and raises an exception when finished producing values.

3.1 filter clauses: if

效果和前面的 filter() 是相同的

给一个具体的例子计算文件非空行的行数

3.2 nested loops: for

4. yield

5. generator

6. user-defined iterable classes

发表评论

电子邮件地址不会被公开。 必填项已用*标注

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d 博主赞过: