天天看点

Python 进阶_迭代器 & 列表解析目录迭代器列表解析列表解析和迭代器

<a href="#%E7%9B%AE%E5%BD%95">目录</a>

<a href="#%E8%BF%AD%E4%BB%A3%E5%99%A8">迭代器</a>

<a href="#iter-%E5%86%85%E5%BB%BA%E7%9A%84%E8%BF%AD%E4%BB%A3%E5%99%A8%E7%94%9F%E6%88%90%E5%87%BD%E6%95%B0">iter 内建的迭代器生成函数</a>

<a href="#%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%9C%A8-for-%E5%BE%AA%E7%8E%AF%E4%B8%AD">迭代器在 for 循环中</a>

<a href="#%E8%BF%AD%E4%BB%A3%E5%99%A8%E4%B8%8E%E5%AD%97%E5%85%B8">迭代器与字典</a>

<a href="#%E8%BF%AD%E4%BB%A3%E5%99%A8%E4%B8%8E%E6%96%87%E4%BB%B6">迭代器与文件</a>

<a href="#%E5%88%9B%E5%BB%BA%E8%BF%AD%E4%BB%A3%E5%99%A8%E5%AF%B9%E8%B1%A1">创建迭代器对象</a>

<a href="#%E5%88%9B%E5%BB%BA%E8%BF%AD%E4%BB%A3%E5%AF%B9%E8%B1%A1%E5%B9%B6%E5%AE%9E%E7%8E%B0%E5%A7%94%E6%89%98%E8%BF%AD%E4%BB%A3">创建迭代对象并实现委托迭代</a>

<a href="#%E8%BF%AD%E4%BB%A3%E5%99%A8%E7%9A%84%E5%A4%9A%E6%AC%A1%E8%BF%AD%E4%BB%A3">迭代器的多次迭代</a>

<a href="#%E5%88%97%E8%A1%A8%E8%A7%A3%E6%9E%90">列表解析</a>

<a href="#%E5%88%97%E8%A1%A8%E8%A7%A3%E6%9E%90%E7%9A%84%E6%A0%B7%E4%BE%8B">列表解析的样例</a>

<a href="#%E5%88%97%E8%A1%A8%E8%A7%A3%E6%9E%90%E5%92%8C%E8%BF%AD%E4%BB%A3%E5%99%A8">列表解析和迭代器</a>

迭代器是一个含有 <code>next()</code> 方法的对象,让我们可以迭代不是序列数据类型但表现出序列行为的对象,所以可以说迭代器为类序列对象提供了一个类序列的接口(只要是实现了 <code>__iter__()</code> 方法的对象,就可以使用迭代器来进行访问)。迭代器从对象的第一个元素开始访问,直到所有的元素被遍历后结束。对于无法通过索引计数来随机访问元素的数据结构(EG. set)而言,迭代器是唯一的访问其自身元素的方式。

NOTE1: 但迭代器是不支持索引计数的,所以迭代器不能回退,只能往前进行迭代。

NOTE2: 迭代器也不是线程安全的,在多线程环境中对可变对象使用迭代器是一个危险的操作。所以一般情况下应该坚持对不可变对象实现迭代器。

NOTE3: 迭代器对象不支持被多次迭代

iter(…)

iter(collection) -&gt; iterator

iter(callable, sentinel) -&gt; iterator

1. 如果传递了一个序列(sequence)实参,迭代器会从索引 0 一直迭代至结束。

2. 如果传递了两个实参 EG. <code>iter(func, sentinel)</code>,迭代器会重复的调用 func 直到迭代器的下一个值为 sentinel 。

EXAMPLE 1:

迭代器通过其内建的 <code>iter.next()</code> 方法,或通过 Python 内建的 <code>next()</code> 来迭代下一个元素,直到最后触发 <code>StopIteration</code> 异常后表示迭代结束。

EXAMPLE 2: 捕获异常

EXAMPLE 3: 对 EXAMPLE 2 的改进

Python 在 for 循环的语法糖中,让 for 循环能够自动的调用迭代器的 <code>next()</code> 方法以及捕获 <code>StopIteration</code> 异常。

字典是一个可迭代对象,其迭代器会变量它的 key, 所以我们可以应用这个特性将语句 <code>for eachKey in myDict.keys()</code> 改进为 <code>for eachKey in myDict</code>

EXAMPLE 4:

文件也是一个可迭代对象,迭代器会自动的调用文件对象的 <code>readline()</code> 方法,所以可以将语句 <code>for eachLine in myFile.readlines()</code> 修改为 <code>for eachLine in myFile</code>

EXAMPLE 5:

EXAMPLE 6: 一个斐波那契数列

Output:

将实例化语句 <code>fab = Fab(5)</code> 修改成 <code>fab = Fab(100)</code> 后执行,再看看 Output:

NOTE: 这一类的应用场景会对内存造成非常大的负担,建议使用迭代器来减少内存的压力。

EXAMPLE 6 中的 <code>__iter__()</code> 方法 return 了自己,所以迭代的对象就是自身。除此之外,我们还可以实现 委托迭代。

委托迭代:就是将迭代请求委托到迭代对象内部持有的容器对象上。它能让自己创建的新容器能够完成迭代操作。

EXAMPLE 7:

EXAMPLE 7 是一个树结构,执行自身(root),返回子节点(Node(1)、Node(2)) 。这个例子,当我们 for 循环遍历迭代器对象 root 时,实际上是迭代了 <code>self._children = [Node(1), Node(2)]</code>,这就是迭代委托。

在上文写到,迭代器不支持被多次迭代,这样实在不能说是灵活。为了解决这一个问题,引入了可迭代对象(iterables)和迭代器对象(iterator)两个不同的概念。

迭代器对象:<code>__iter__()</code> 返回的是迭代器对象自身。

可迭代对象:<code>__iter__()</code> 返回了一个迭代器对象。

上述的 委托迭代 就是一个返回一个迭代器对象的例子,所以 EXAMPLE 7 是一个 可迭代对象,他能够被多次迭代。

是一个非常有用、简单且灵活的工具,让我们能够动态的创建列表类型对象。

语法:

上面两条语句的效果是一样的,但列表解析的方法仅调用一次 <code>range(10)</code>, 而第二条则调用了 <code>map()/lambda/range(10)</code>,这说明列表解析可以替代 map() 以及 lambda ,以此来获取更高的效率。

嵌套 for 循环实现的矩阵

统计文件单词数

求素数

嵌套列表降维

因为 for 循环的关系,所以从上面的例子可以看出列表解析和迭代器之间的关系非常紧密。深入的理解两者,对提高 Python 程序的效率有非常大的帮助。迭代是 Python 一个非常重要的思想和特性。