【Python学习手册(第四版)】学习笔记13.2-循环技巧

个人总结难免疏漏,请多包涵。更多内容请查看原文。本文以及学习笔记系列仅用于个人学习、研究交流。

本文紧接着上一篇while、for循环后,主要介绍循环技巧。包括循环计数器(while、range)、非完备遍历(range、分片)、修改列表、并行遍历,以及zip构造字典、最后是偏移和元素enumerate。可以看到range、分片、zip、enumberate是比较常用的循环技巧。5-10分钟阅读完成,多用多熟。


目录

编写循环技巧

循环计数器:while和range

非完备遍历:range和分片

修改列表:range

并行遍历:zip

zip构造字典

产生偏移和元素:enumerate


编写循环技巧

for循环包括多数计数器式的循环。一般而言,for比while容易写,执行时也比较快。每当需要遍历序列时,都应该把for循环作为首选的工具。但是,有些情况下需要以更为特定的方式来进行迭代。

例如,如果需要在列表中每隔一个元素或每隔两个元素访问,或者在过程中修改列表?如果在同一个for循环内,并行遍历一个以上的序列?

可以用while循环以及手动索引运算编写这类独特的循环,python提供了两个内置函数,在for循环内定制迭代:

·内置range函数返回一系列连续增加的整数,可作为for中的索引。

·内置zip函数返回并行元素的元组的列表,可用于在for中内遍历数个序列。

for循环比while循环速度更快,为了更具优势,下面来学习这些函数。

循环计数器:while和range

range函数是通用的工具,常用在for循环中产生索引,但也可用在任何需要整数列表的地方。在Python中,range是一个迭代器,会根据需要产生元素,因此,我们需要将其包含到一个list调用中以一次性显示其结果:

list(range(5)),list(range(3,5)),list(range(0,10,2))
([0, 1, 2, 3, 4], [3, 4], [0, 2, 4, 6, 8])

传一个参数时,range会计算从0开始的整数,但不包括传入的参数值

传2个参数时,第一个将视为下边界。第三个选用参数可以提供步进值。

使用时,Python会对每个连续整数加上步进值从而得到结果(步进值默认为1)。range也可以是非正数或非递增的:

list(range(-5,5))
[-5, -4, -3, -2, -1, 0, 1, 2, 3, 4]

list(range(5,-5,-1))
[5, 4, 3, 2, 1, 0, -1, -2, -3, -4]

range是for循环中最常用的,它提供一种简单的方法,重复特定次数的动作。

例如,要打印3行时,可以使用range产生适当的整数数字;在Python中,for循环迫使range的结果自动化,因此在这里不必列出:

range也常用来间接地迭代一个序列。遍历序列最简单并且是最快的方式就是使用简单的for,让Python处理大多数的细节。

for循环以这种方式使用时,会自动处理迭代的细节。如果真的想要明确地掌控索引逻辑,可以用while循环来实现。

i = 0
while i < len(x):
    print(x[i],end=' ')
    i += 1

也可以使用for进行手动索引,也就是用range产生用于迭代的索引的列表。这是一个多步骤的过程,但是,对于产生偏移值(而不是产生位于那些偏移值的元素)来说足够了:

这个例子是步进X的偏移值的列表,而不是X实际的元素。

需要在循环中对X进行索引运算从而取出每个元素。

非完备遍历:range和分片

上一节最后例子可以实现,但同时要求我们做更多。

除非有特殊的索引需求,不然在可能的情况下,最好使用Python中的简单的for循环,不要用while,并且不要在for循环中使用range调用,只将其视为最后的手段。更简单的办法总是更好的。

上一个例子中所用的编码样式可做更特殊的遍历种类。

例如,在遍历的过程中跳过一些元素。

这里通过使用所产生的range列表,访问了字符串S中每隔一个的元素。要使用每隔两个的元素,可以把range的第三参数改为3,依此类推。

实际上,通过这种方式使用range来跳过循环内的元素,依然保持了for循环的简单性。

这可能不是如今Python中理想情况下最现实的技术。分片表达式,提供了实现相同目标的更简单的办法。例如,要使用S中每隔一个的字符,可以用步进值2来分片:

结果是相同的,但更容易编写,对其他人来说更容易阅读。与之相比,使用range唯一的真正优点是——它没有复制字符串,并且不会在Python中创建一个列表,对于很大的字符串来说,这会节省内存。

修改列表:range

可以使用range和for的组合的常见场合就是在循环中遍历列表时并对其进行修改。

例如,假设因某种理由要为列表中每个元素都加1。但是可能做不出想要的效果:

为什么?因为修改的是循环变量x,而不是列表L。每次经过循环时,x会引用已从列表中取出来的下一个整数。例如,第一轮迭代中,x是整数1。下一轮迭代中,循环主体把x设为不同对象,也就是整数2,但是并没有更新1所来自的那个列表。

要在遍历列表时对其进行修改,需要使用索引,可以在遍历时替每个位置赋一个已更新的值。range/len组合可以替我们产生所需要的索引。

随着循环的执行,列表中的内容会改变。

没有办法用简单的for x in L:循环做相同的事,因为这种循环会遍历实际的元素,而不是列表的位置。但是,等效的while循环又如何呢?这种循环需要我们多做些工作,并且有可能运行得更慢。

在这里,range的解决方案也不理想。

列表解析表达式也能做类似的工作,而且没有对最初的列表进行在原处的修改(我们可以把表达式的新列表对象赋值给L,但是这样不会更新原始列表的其他任何引用值)

l = [1,2,3,4,5,6]
l1 = [x+1 for x in l]
l1
[2, 3, 4, 5, 6, 7]

并行遍历:zip

内置函数range允许在for循环中以非完备的方式遍历序列。内置的zip函数也可以使用for循环来并行使用多个序列。在基本运算中,zip会取得一个或多个序列为参数,然后返回元组的列表,将这些序列中的并排的元素配成对。

例如,假设我们使用两个列表:

要合并这些列表中的元素,可以使用zip来创建一个元组对的列表(和range一样,zip在Python中也是一个可迭代对象,因此必须将其包含在一个list调用中以便一次性显示所有结果):

搭配for循环时,它就会支持并行迭代。

在这里步进获得了zip调用的结果,即从两列表中提取出来的元素配对。

注意:这个for循环在这里使用元组赋值运算以解包zip结果中的每个元组。第一次迭代时,就好像执行了赋值语句(x,y)=(1,5)。结果就是在循环中扫描L1和L2。

也可以用while循环手动处理索引,以达到类似的效果,但是需要更多的输入,而且可能始终比for/zip办法实现得慢。

严格来讲,zip函数比这个例子更为一般化。例如,zip可以接受任何类型的序列(其实就是任何可迭代的对象,包括文件),并且可以有两个以上的参数。对于3个参数,像如下的例子那样,它构建了3元素元组的一个列表,其中带有来自每个序列的元素,基本上按照列对应(从技术上讲,会得到N个参数的一个N维元组)。

参数长度不同时,zip会以最短序列的长度为准来截断所得到的元组。

下面的例子中,把两个字符串zip到一起以并行地选取字符,但是结果所拥有的元组数只和最短的序列的长度一致:

zip构造字典

当键和值的集合必须在运行时计算时,zip调用也可用于产生字典,并且使用非常方便。

如果要在脚本写好后,在运行时获得字典键和值的列表,那该怎么做呢?

例如,假设有下列的键和值的列表:

将这些列表变成字典的一种做法就是将这些字符串zip起来,并通过for循环并行步进处理。

后续版本中,你可以完全跳过for循环,直接把zip过的键/值列表传给内置的dict构造函数

内置变量名dict其实是Python中的类型名称,对它进行调用的时候,可以得到类似列表到字典的转换。

产生偏移和元素:enumerate

通过range来产生字符串中元素的偏移值,而不是那些偏移值处的元素。不过,在有些程序中,我们两者都需要:要用的元素以及这个元素的偏移值。

从传统意义上来讲,这是简单的for循环,它同时也持有一个记录当前偏移值的计数器。

Python版本中,有个新的内置函数,名为enumerate,可以做这件事。

enumerate函数返回一个生成器对象:这个对象有一个__next__方法,由下一个内置函数调用它,并且循环中每次迭代的时候它会返回一个(index,value)的元组。

可以在for循环中通过元组赋值运算将元组解包(很像是使用zip):

  • 16
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

兴焉

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值