返回介绍

例子

发布于 2024-01-29 22:24:16 字数 4821 浏览 0 评论 0 收藏 0

我们现在在交互模式下输入一些for循环,来看看在实际应用中它们是如何使用的。

基本应用

就像前边介绍的一样,for循环可以遍历任何一种序列对象。例如,在第一个例子中,我们把变量名x依次由左至右赋值给列表中三个元素的每一个,而print语句将会每个元素都执行一次。在print语句内(循环主体),变量名x引用的是列表中的当前元素。

下面的两个例子会计算列表中所有元素的和与积。本章和本书后面,我们会介绍一些工具,可以自动对列表中的元素应用诸如“+”和“*”类似的运算,但是使用for循环通常也一样简单。

其他数据类型

任何序列都适用for循环,因它是通用的工具。例如,for循环可用于字符串和元组。

实际上,稍后我们就会知道,for循环甚至可以应用在一些根本不是序列的对象上,对于文件和字典也有效!

在for循环中的元组赋值

如果迭代元组序列,循环目标本身实际上可以是目标元组。这只是元组解包的赋值运算的另一个例子而已。记住,for循环把序列对象元素赋值给目标,而赋值运算在任何地方工作起来都是相同的。

在这里,第一次走过循环就像是编写(a,b)=(1,2),而第二次就像是编写(a,b)=(3,4),依次类推。这不是特殊情况;任何赋值目标在语法上都能用在for这个关键字之后。

这种形式通常和我们在本章后面所介绍的zip调用一起使用,以实现并行遍历。在Python中,它通常还和SQL数据库一起使用,其中,查询结果表作为这里使用的列表这样的序列的序列而返回——外围的列表就是数据库表,嵌套的元组是表中的行,元组赋值和列对应。

for循环中的元组使得用items方法来遍历字典中的键和值变得很方便,而不必再遍历键并手动地索引以获取值:

注意for循环中的元组赋值并非一种特殊情况,这一点很重要;单词for之后的任何赋值目标在语法上都是有效的。尽管我们总是在for循环中手动地赋值以解包:

在遍历序列的序列的时候,循环头部的元组为我们节省了一个额外的步骤。正如第11章所介绍的,在一个for中,即便嵌套的结构也能够以这种方式自动解包:

但这不是特殊情况——在每次迭代上,for循环直接运行我们在其之前运行的那种赋值。任何嵌套的序列结构都可以按照这种方式解包,只不过因为序列赋值是如此通用:

Python 3.0在for循环中扩展的序列赋值

实际上,由于for循环中的循环变量真的可以是任何赋值目标,在这里,我们也可以使用Python 3.0的扩展序列解包赋值语法,来提取序列中的序列的元素和部分。实际上,这也不是特殊情况,只不过是Python 3.0中的一种新的赋值形式(正如本书第11章所介绍),因为它在赋值语句中有效,它自动地在for循环中有效。

考虑前面小节介绍的元组赋值形式。在每次迭代时,值的一个元组赋给了名称的一个元组,就像是一条简单的赋值语句一样:

在Python 3.0中,由于一个序列可以赋值给一组更为通用的名称(其中有一个带有星号的名称收集多个元素),我们可以在for循环中使用同样的语法来提取嵌套的序列的部分:

实际上,这种方式可以用来从表示为嵌套序列的数据的行中选取多个列。在Python 2.X中,带星号的名称是不允许的,但是,我们可以通过分片实现类似的效果。唯一的区别是分片返回一个特定类型的结果,而星号名称总是赋值一个列表:

参见第11章了解这种赋值形式的更多内容。

嵌套for循环

现在,我们来学习复杂一点的for循环。下一个例子是在for中示范循环else分句以及语句嵌套。考虑到对象列表(元素)以及键列表(测试),这段代码会在对象列表中搜索每个键,然后报告其搜索结果。

因为这里的嵌套if会在找到相符结果时执行break,而循环else分句是认定如果来到此处,搜索就失败了。注意这里的嵌套。当这段代码执行时,同时有两个循环在运行:外层循环扫描键列表,而内层循环为每个键扫描元素列表。循环else分句的嵌套是很关键的,其缩进至和内层for循环首行相同的层次,所以是和内层循环相关联的(而不是if或外层for)。

注意:如果我们采用in运算符测试成员关系,这个示例就会比较易于编写。因为in会隐性地扫描列表来找到匹配,因此可以取代内层循环。

一般来说,基于对简洁和性能的考虑,让Python尽可能多做一点工作,这是个好主意,就像这个问题的解法中所展示的那样。

下一个例子以for执行典型的数据结构任务:收集两个序列(字符串)中相同元素。这差不多是简单的集合交集的例程。在循环执行后,res引用的列表中包含seq1和seq2中找到的所有元素。

可惜的是,这个程序代码只能用在两个特定的变量上:seq1和seq2。如果这个循环可以通用化成为一种工具,可以使用多次,结果就会很棒。以后你就会知道,这个简单的想法会把我们引向函数,也就是本书下一部分的主题。

为什么要在意“文件扫描”

一般来说,每当你需要重复一个运算或重复处理某件事的时候,循环就很方便。因为文件包含了许多字符和行,它们也是循环常见的典型使用案例之一。要把文件内容一次加载至字符串,你可以调用read:

但是,要分块加载文件,通常要么是编写一个while循环,在文件结尾时使用break,要么写个for循环。要按字符读取时,下面的两种代码编写的方式都可行。

这里的for也会处理每个字符,但是会一次把文件加载至内存。要以while循环按行或按块读取时,可以使用类似于下面的代码。

通常是按照块读入二进制数据的。不过,逐行读取文本文件时,for循环是最易于编写以及执行最快的选择。

文件readlines方法会一次把文件载入到行字符串的列表,这里的最后的例子则按照文件迭代器来自动在每次循环迭代的时候读入一行(迭代器将会在第14章中讨论)。参见库手册以了解关于这里用到的调用的更多内容。这里的最后一个例子通常是文本文件的最佳选择——它除了简单,还对任意大小的文件都有效,并且不会一次把整个文件都载入到内存中。迭代器版本可能会更快,但是在Python 3.0中I/O性能稍差。

在一些Python 2.X代码中,也可以看到open替代为file以及文件对象的较早的xreadlines,以实现与文件的自动行迭代器同样的效果(它就像是readlines,但是不会一次把文件载入到内存中)。Python 3.0中删除了file和xreadlines,因为它们都是多余的;也不能在Python 2.6中使用它们,但是,可能会在更早的代码和资源中出现。参阅第36章了解关于读取文件的更多内容,在那里将会看到,文本文件和二进制文件在Python 3.0中的含义有细微的差别。

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文