迭代器和解析——Python(学习笔记)

本篇文章主要介绍Python的迭代协议的相关概念——for循环使用的一种方法调用模式。

“可迭代对象”——可迭代对象的概念在Python中是相当新颖的,但在语言设计中很普遍。基本上这就是序列观念的通用化:如果对象是实际保存的序列,或者可以在迭代工具环境中一次产生一个结果的对象,就可以看作是可迭代的。总之,可迭代的对象包括实际和按照需求而计算的虚拟序列。

迭代器:初探

for 循环可以用于Python中任意序列类型,包括列表、元组、字符串、字典等:

<span style="font-size:18px;">>>> for i in [1,2,3,4]:
...     print i
... 
1
2
3
4
>>> for i in (1,2,3,4):
...     print i
... 
1
2
3
4
>>> for i in "hello":
...     print i*2
... 
hh
ee
ll
ll
oo
</span>

文件迭代器:

了解文件迭代器的简单方式之一就是看他如何与内置类型一起工作:

>>> f = open('myfile.txt','r')
>>> f.readline().strip('\n')
'hello'
>>> f = open('myfile.txt','r')
>>> f.readline().strip('\n')     //使用readline()方法可以一次读取文件的一行
'hello'
>>> f.readline().strip('\n')
'i'
>>> f.readline().strip('\n')
'love'
>>> f.readline().strip('\n')
'python'
>>> f.readline().strip('\n')   //<span style="color:#3333FF;">到达文件末尾时就会返回空字符串,(可以使用检测空字符串的方法跳出循环)</span>
''

如今在高版本例如Python3.0中,文件也有一个方法:_next_,和readline()有差不多的效果:每次调用时就会返回文件中的下一行。唯一值得注意区别的是,到达文件末尾时,_next_会引发内置法人StopIteratin异常,而不是返回空字符串:

使用方法:

>>> f = open('myfile.txt','r')
>>> f._next_()

迭代读取文件内容:

<span style="font-size:18px; "></span><pre name="code" class="python" style="margin-top: 4px; margin-right: 0px; margin-bottom: 4px; margin-left: 0px; background-color: rgb(240, 240, 240); ">>>> f = open('myfile.txt','r')
>>> for line in f:
...     if line =='':
...             break
...     print line.strip('\n')
... 
hello
i
love
python

 

>>> for line in open('myfile.txt').readlines():
...     print line.upper().strip('\n')
... 
HELLO
I
LOVE
PYTHON

>>> f = open('myfile.txt','r')
>>> while True:
...     line = f.readline().strip()
...     if not line:
...             break
...     print line
... 
hello
i
love
python


使用while循环会得到和上述代码一样的效果,但是比起for循环的迭代器,这样可能会慢一些:

>>> f = open('myfile.txt','r')
>>> while True:
...     line = f.readline()
...     if line == '':
...             break
...     print line.strip()
... 
hello
i
love
python

其他内置类型的迭代器:

除了文件以及列表这样的实际序列外,其他类型也有其适用的迭代器。

例如:遍历字典键的经典方法就是明确的获取其键的列表

>>> D = {'a':'i','b':'love','c':'python'}
>>> for key in D.keys():
...     print key+","+ D[key]
... 
a,i
c,python
b,love


不过在最近的Python版本中,字典有一个迭代器,在迭代环境中,会自动返回一个键:

>>> D = {'a':1,'b':2,'c':3}
>>> I = iter(D)
>>> next(I)
'a'
>>> next(I)
'c'
>>> next(I)
'b'
>>> next(I)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
StopIteration
>>> 

直接效果是,不需要再调用keys的方法来调用字典——for循环将使用迭代协议在每次迭代的时候获取一个键。

>>> for key in D:
...     print key,D[key]
... 
a 1
c 3
b 2

列表解析

列表解析是最常应用迭代协议的环境之一:

>>> L = [1,2,3,4,5,6]
>>> for i in range(len(L)):
...     L[i] += 10
... 
>>> L
[11, 12, 13, 14, 15, 16]
上述例子是有效的,但是他可能不是Python中的优化的“最佳实践”。如今,列表解析表达式使得早先许多例子变得过时了。例如:我们可以用产生所需的结果列表的一个单个表达式来替代该循环:

>>> L = [i+10 for i in L ]
>>> L
[21, 22, 23, 24, 25, 26]

直接结果是相同的,但是它需要较少的代码,并且可能会运行的更快,但是列表解析并不是必须的,因为我们总是可以用一个for循环手动的构建一个表达式结果的列表:

>>> res = []
>>> for x in L:
...     res.append(x+10)
... 
>>> res
[31, 32, 33, 34, 35, 36]

实际上这和列表解析做着同样的事情。,但是列表解析比手动for循环语句运行的更快。


在文件上使用列表解析:

文件上使用列表解析是另一个常见用例

>>> f = open("myfile.txt")
>>> lines = f.readlines()
>>> lines
['hello\n', 'i\n', 'love\n', 'python\n']
>>> 

文件对象中有一个readlines()方法,它能一次性的把文件载入到行字符串的一个列表中。

在结果中的行在末尾都包含了一个换行符号(\n)。对于很多程序来说,换行符很讨厌,我们必须小心避免打印的时候留下双倍的空白

<span style="font-size:18px; "></span><pre name="code" class="python" style="margin-top: 4px; margin-right: 0px; margin-bottom: 4px; margin-left: 0px; background-color: rgb(240, 240, 240); ">>>> lines = [line.rstrip() for line in lines]
>>> lines
['hello', 'i', 'love', 'python']
>>> lines = [line.rstrip() for line in open("myfile.txt")]
>>> lines
['hello', 'i', 'love', 'python']
>>> lines = [ line.strip('\n') for line in open("myfile.txt")]
>>> lines
['hello', 'i', 'love', 'python']
>>> lines = [ line[:-1] for line in open("myfile.txt")]
>>> lines
['hello', 'i', 'love', 'python']

 

在文件上使用列表解析不仅具有高效性而且其表现能力也很强。我们可以在迭代时在一个文件的行上运行任何字符串操作:

>>> f = open("myfile.txt")
>>> lines = f.readlines()
>>> lines 
['hello\n', 'i\n', 'love\n', 'python\n']
>>> lines = [line.upper() for line in lines]
>>> lines
['HELLO\n', 'I\n', 'LOVE\n', 'PYTHON\n']
>>> lines = [line.upper().rstrip() for line in lines]
>>> lines
['HELLO', 'I', 'LOVE', 'PYTHON']
>>> [line.split() for line in lines]
[['HELLO'], ['I'], ['LOVE'], ['PYTHON']]
>>> [line.replace('','!') for line in lines]
['!H!E!L!L!O!', '!I!', '!L!O!V!E!', '!P!Y!T!H!O!N!']
>>> [line.replace(' ','!') for line in lines]
['HELLO', 'I', 'LOVE', 'PYTHON']

扩展的列表解析语法:

作为一个特别有用的扩展,表达式中嵌套的for循环可以有一个相关的if子句来过滤那些测试不为真的结果。

>>> line = [line.rstrip() for line in open("myfile.txt") if line[0] == 'l']
>>> line
['love']
这条if语句检查从文件读取的每一行,检查第一个字符是否为'l',,如果不是从结果列表中省略该行
总是可以把一个列表解析转换为for循环语句(但是这种表达方式运行起来要慢很多,而且占据行数也比较多)

>>> res = []
>>> for line in open("myfile.txt"):
...     if line[0] == 'l':
...             res.append(line.rstrip())
...     else:
...             pass
... 
>>> res
['love']
如果我们需要的话,列表解析可以变得更复杂:

>>> [x+y for x in 'abc' for y in 'cde']
['ac', 'ad', 'ae', 'bc', 'bd', 'be', 'cc', 'cd', 'ce']

再次理解这个表达式的一种方式是通过缩进其各个部分将它转换为语句的形式,下面是其等价形式,但可能会慢一些,这是实现相同效果的一种代方式:

>>> res = []
>>> for x in 'abc':
...     for y in 'edc':
...             res.append(x+y)
... 
>>> res
['ae', 'ad', 'ac', 'be', 'bd', 'bc', 'ce', 'cd', 'cc']


参考:Python学习手册

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值