购买
下载掌阅APP,畅读海量书库
立即打开
畅读海量书库
扫码下载掌阅APP

1.1 Python中的迭代

Python内置了名为iter()的函数。当向iter()函数传入可迭代对象时,iter()会返回迭代器对象:

迭代器是个对象,可以逐个生成序列中的值:

不需要直接调用iter()。当使用for循环,如for num in numbers时,Python会自动在底层调用iter()。返回的对象会作为for循环的迭代器:

集合的迭代器是独立对象,拥有唯一id,可借助id()函数进行确认:

iter()有多种获取迭代器的方法,其中之一是使用魔术方法__iter__()。任意类都能定义魔术方法,且不需要传入参数。每次调用__iter__()时,就会生成一个新的迭代器对象。例如,列表就内置了__iter__()方法:

Python对迭代器对象和可迭代对象进行了区分。判定一个对象是否可迭代,唯一的条件是能否将其传递给iter()函数,然后得到可以直接使用的迭代器。如果该对象具有__iter__()方法,iter()就会调用__iter__()方法获取迭代器。Python中的列表和元组都是可迭代的,字符串也是可迭代的,所以才能用for char in my_str:语句迭代字符串my_str中的字符。一般而言,可用于for循环的任何容器类对象都是可迭代的。

for循环是最常见的迭代序列的方法。不过,代码有时需要更细致地迭代序列。这时,可以借助内置函数next()。使用next()时需要传入参数,即迭代器。每次调用next(my_iterator)时,即可获取并返回下一个元素:

如果再次调用next(names_it),则会触发特定的内置异常,即StopIteration:

迭代器抛出特定异常StopIteration,表明序列已结束。通常情况下,不需要手动抛出或捕获StopIteration异常,后文会介绍StopIteration的用法。对于理解for循环的运行机制,可以认为for循环每次运行时,都会在内部调用next()方法。抛出StopIteration异常后,退出循环。

在调用next()时,可以额外添加一个参数,用于指定默认值。如此一来,当迭代到序列末尾时,next()函数就不会抛出StopIteration异常,而是返回预设的默认值:

再考虑另一种情况。倘若处理的不是简单的数值序列,而是需要通过计算、读取或其他方式获取序列元素,又该如何操作呢?

看一个简单的例子。假设需要编写一个创建平方数列表的函数:

该函数可以运行,但其中潜藏着问题,你能发现吗?

问题之一,假如MAX的值不是5,而是10 000 000或是10 000 000 000,甚至是更大的值,那么代码会占用大量内存。创建如此庞大的列表后,仅使用一次就丢弃了,这样的内存占用在一定程度上是毫无意义且可怕的。此外,必须等待所有平方值都计算完毕,for循环才能开始运行。若有用户使用该程序,或许会怀疑程序卡住了。

更严重的问题是,若不采用运算快速且资源消耗低的算术方法获取每个元素,而是执行非常耗费资源的计算,或是通过网络调用API,又或是从数据库读取数据,那么程序就会运行得特别慢,毫无响应,甚至因内存不足而出现程序崩溃的情况。此时用户一定会质疑程序员的编程水平。

最好的解决方案是先创建迭代器,仅在需要值时,以惰性计算的方式进行计算。这样就能保证循环的每一步执行都是即时的。

那么,该如何实现呢?有多种实现方法,最佳方法是使用生成器函数。你肯定会爱不释手! qtGFA9OIfjuouGTp7PxT9uC54N+RADCJUv8X+uEKsRSrGQ/E2FH4eo3PG+liQvWD

点击中间区域
呼出菜单
上一章
目录
下一章
×