尽管while和for循环能够执行大多数重复性任务, 但是由于序列的迭代需求如此常见和广泛, 以至于Python提供了额外的工具以使其更简单和高效. 迭代器在Python中是以C语言的速度运行的, 而且迭代器的版本根据每次发行而改进, 所以它的运行速度更快.

while一般比for的效率更低些, for循环通过不同的写法可以完全可以替代while循环, 所以当在while和for中选择时,用for循环吧

迭代器

迭代器初探

for循环可以用于Python中任何序列类型, 包括列表以及元组以及字符串. 实际上for循环更加通用:可用于任何可迭代对象.实际上, python中所有的会从左到右扫描对象的迭代工具都是如此通用, 这些迭代工具包括 for循环, 列表解析, in成员关系测试, map内置函数等

>>> for i in [1, 2, 3]:print(i, end=' ')
1 2 3 >>> for i in (1, 2, 3):print(i, end=' ')
1 2 3 >>> for i in "apple":print(i, end=' ')
a p p l e

可迭代对象

序列概念的通用化,如果对象是实际保存的序列或者迭代环境中一次产生一个结果的对象, 就可以看做是可迭代的

文件迭代器

看看迭代器和内置类型如何工作的,例如文件, 已经打开的文件对象有个方法readline(), 可以一次从文本中读取下一行(包括行末标识符)到一个字符串, 每次调用readline(),就会前进到下一行, 到达文件末尾返回空字符串, 我们通过它来检测, 从而跳出循环.

>>> f = open("/Users/mac/Documents/path.py")
>>> f.readline()
'import sys\n'
>>> f.readline()
'print(sys.path)\n'
>>> f.readline()
'print("hello heathty")\n'
>>> f.readline()
''
>>> f.readline()
''

文件也有一个方法为 __next__(), 每次调用就会返回文件的下一行, 应该注意的区别是到达文件末尾 __next__()会引发内置的StopIteration异常, 而不是空字符串

>>> f = open("/Users/mac/Documents/path.py")
>>> f.__next__()
'import sys\n'
>>> f.__next__()
'print(sys.path)\n'
>>> f.__next__()
'print("hello heathty")\n'
>>> f.__next__()
StopIteration
>>>

这个接口就是Python的迭代协议:

1. 有__next__() 方法的对象会前进到下一个结构, 而在末尾会引发StopIteration异常.

2. 在Python中任何这类对象都认为是可迭代的.任何这类对象也能以for循环或者其他迭代工具遍历

3. 所有的迭代工具内部工作都是在每次迭代中调用__next__(), 并且捕捉StopIteration异常来确定何时离开

文件对象有个方法readlines(), 它会在调用时一次把所有的文件加载到内存, 如果文件太大, 以至于计算机内存不够, 甚至不能工作; 而迭代器一次读取一行到内存,可以避免这个问题

>>> for line in open("/Users/mac/Documents/path.py").readlines():
print(line.upper(), end=' ')
IMPORT SYS
PRINT(SYS.PATH)
PRINT("HELLO HEATHTY") # 迭代器
>>> for line in open("/Users/mac/Documents/path.py"):
print(line.upper(), end=' ') IMPORT SYS
PRINT(SYS.PATH)
PRINT("HELLO HEATHTY")

手动迭代: iter 和 next

为了支持手动迭代代码, Python3.0提供了内置函数next(), 它会自动调用一个对象的__next__()方法, 调用next(X) 等同于X.__next__(),

>>> f = open("/Users/mac/Documents/path.py")
>>> next(f)
'import sys\n'
>>> next(f)
'print(sys.path)\n'
>>> next(f)
'print("hello heathty")\n'
>>> next(f)
StopIteration
>>>

技术角度来说迭代协议还有一点值得注意. 当for循环开始的时, 会通过for可迭代对象传递给iter内置函数, 以便可迭代对象获取一个迭代器, 返回对象含有__next__()方法.

我们下面看看for循环内部如何处理列表这类内置类型吧

>>> L = [1, 2, 3]
>>> L is iter(L)
False
>>> L.__next__()
AttributeError: 'list' object has no attribute '__next__'
>>> I = iter(L)
>>> I.__next__()
1
>>> I.__next__()
2
>>> I.__next__()
3
>>> I.__next__()
StopIteration
>>>

这一步 I = iter(L) 对于文件来说不是必须的, 因为文件自己就是自己的迭代器, 也就是说文件自己就有__next__()方法, 因此不需要返回一个不同的对象:

>>> f = open("/Users/mac/Documents/path.py")
>>> iter(f) is f
True
>>> f.__next__()
'import sys\n'
>>>

列表以及很多其他内置对象,不是自身的迭代器, 因为它们支持多次打开迭代器, 对这样的对象, 我们必须要iter()内置函数来启动迭代

注意字典中 , 遍历字典的经典方法是明确的获取字典的键的列表; 在Python3.0中, 字典有一个迭代器在迭代环境中,会自动一次返回一个键.


>>> D = dict(a=1, b=2, c=3)
>>> D
{'c': 3, 'b': 2, 'a': 1}
>>> for k in D.keys():print(k)
c
b
a
>>> for k in D:print(k)
c
b
a
>> I = iter(D)
>>> next(I)
'c'
>>> next(I)
'b'
>>> next(I)
'a'
>>> next(I)
StopIteration
>>>

列表解析

列表解析是最常用的迭代协议之一, 经常与for循环一起使用,下面来看看例子

一般修改列表时, 通过遍历列表的元素, 使用range来修改它; 现在有个更加简洁的方法来达到, 我们可以通过产生所需列表的一个单个表达式来替换该循环.

>>> L = [1, 1, 2, 3, 5]
>>> for i in range(len(L)):
L[i] += 2
>>> L
[3, 3, 4, 5, 7] >>> L = [i + 10 for i in L]
>>> L
[13, 13, 14, 15, 17]
>>>

上述两种方式结果相同, 但是列表解析更加简洁, 并且可能运行更快, 列表解析并不完全和for循环语句版本相同, 因为它会产生一个新的列表对象; 此外列表解析比手动的for循环语句运行更快(大约一倍), 因为他们的迭代在解释器内部是以C语言的速度执行.

列表解析基础知识

 L = [i + 10 for i in L]

1. 组成:

  • 列表解析写在一个方括号 [ ]中, 因为它们是最终构建一个新的列表的一种方式;
  • 它以我们组成的一个任意表达式开始, 该表达式使用后面for循环申明的循环变量;
  • 后面的for循环申明循环变量, 以及一个可迭代对象

2. 运行

运行该表达式, Python在解释器内部执行一个遍历L的迭代, 按照顺序把 i 赋值到表达式中, 并且收集表达式的运算结果, 得到一个新列表.

扩展的列表解析语法

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

>>> L = [4, 5, 7, 9, 12]
>>> [i for i in L if(i%4 ==0)]
[4, 12]
>>>

如果我们需要的话, 列表解析可以更加复杂:

他们可以包含任意嵌套的循环, 也可能被编写为一系列子句.实际上, 他们完整的语法允许任意数目的子句, 每个子句有一个可选的相关if子句

>>> [x+y for x in "ab" for y in "mn"]
['am', 'an', 'bm', 'bn']

其他迭代环境

map:

  1. 内置函数, 它把一个函数调用应用于传入的可迭代对象中的每一项,
  2. 它有局限性, 因为它需要一个函数,而不是一个任意表达式.
  3. Python3.0中 map返回一个可迭代对象自身, 因此我们需要将它包含到一个list调用已迫使一次性给出所有值

sorted排序可迭代对象的各项;

zip组合可迭代对象的各项;

enumerate根据相对位置匹配可迭代对象的项;

filter选择一个函数为真的项;

reduce针对可迭代对象的成对的项运行一个函数;

range() 内置函数, 返回可迭代对象,

所有这些接受一个可迭代对象, Python3.0中zip,enumerate, filter也像map一样返回一个可迭代对象. 他们都是自己的迭代器----在遍历结果一次之后, 游标就到底了, 没法在此使用__next__()方法了

>>> f = open("/Users/mac/Documents/path.py")
>>> sorted(f)
['import sys\n', 'print("hello heathty")\n', 'print(sys.path)\n'] >>> list(zip(open("/Users/mac/Documents/path.py"), open("/Users/mac/Documents/path.py")))
[('import sys\n', 'import sys\n'), ('print(sys.path)\n', 'print(sys.path)\n'), ('print("hello heathty")\n', 'print("hello heathty")\n')] >>> list(enumerate(open("/Users/mac/Documents/path.py")))
[(0, 'import sys\n'), (1, 'print(sys.path)\n'), (2, 'print("hello heathty")\n')]
>>> >>> l = [0, 1, 3]
>>> list(filter(bool, l))
[1, 3]
>>>
>>> import functools ,operator
>>> functools.reduce(operator.add, l)
4

多个迭代器 vs 单个迭代器

range 它不是自己的迭代器(手动迭代, 我们使用iter 产生一个迭代器), 并且它支持器结果上的多个迭代器, 这些迭代器会记住各自的位置:

>>> R = range(3)
>>> R
range(0, 3)
>>> next(R)
TypeError: 'range' object is not an iterator
>>> I1 = iter(R)
>>> next(I1)
0
>>> next(I1)
1
>>> I2 = iter(R)
>>> next(I2)
0
>>>

zip, map, filter不支持相同结果上的多个活跃迭代器

>>> z = zip([1, 2, 3],['a', 'b', 'c'])
>>> list(z)
[(1, 'a'), (2, 'b'), (3, 'c')]
>>> I1 = iter(z)
>>> I2 = iter(z)
>>> next(I1)
StopIteration # 由于上面list(z), 让迭代器的游标知道底部了 >>> z = zip([1, 2, 3],['a', 'b', 'c'])
>>> I1 = iter(z)
>>> I2 = iter(z)
>>> next(I1)
(1, 'a')
>>> next(I1)
(2, 'b')
>>> next(I2)
(3, 'c')
>>> next(I2)
StopIteration

字典视图迭代器

Python3.0中, 字典的keys(), values(), items()方法返回字典视图对象, 他们每次产生一个结果, 而不是在内存中一次产生全部的可迭代对象.

视图保持了和字典中那些项相同的物理顺序, 并且反映底层的字典做出的修改.

下面以keys()方法为例说明, values()与items()与之相同


>>> D = dict(a=1, b=2, c=3)
>>> D
{'b': 2, 'a': 1, 'c': 3}
>>> K = D.keys()
>>> K
dict_keys(['b', 'a', 'c'])
>>> next(K)
TypeError: 'dict_keys' object is not an iterator
>>> I = iter(K)
>>> next(I)
'b'
>>>

Python 迭代器之列表解析的更多相关文章

  1. Python 迭代器之列表解析与生成器

     [TOC] 1. 列表解析 1.1 列表解析基础 列表解析把任意一个表达式应用到一个迭代对象中的元素 Python内置ord函数会返回一个字符的ASCII整数编码(chr函数是它的逆过程, 它将A ...

  2. Python 迭代器和列表解析

    Python 迭代器和列表解析 1)迭代器 一种特殊的数据结构,以对象形式存在 >>> i1 = l1.__iter__() >>> i1 = iter(l1) 可 ...

  3. julia与python中的列表解析.jl

    julia与python中的列表解析.jl #=julia与python中的列表解析.jl 2016年3月16日 07:30:47 codegay julia是一门很年轻的科学计算语言 julia文档 ...

  4. Python中的列表解析和生成器表达式

    Python中的列表解析和生成器表达式 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.列表解析案例 #!/usr/bin/env python #_*_coding:utf-8 ...

  5. Python学习笔记(迭代,列表解析,生成器)

    迭代(iterable):支持每次返回自己所包含一个对象的 iter()得到迭代器,.next()遍历列表. 列表解析:根据已有列表高效生成列表的方式. 生成器(Generator): 通过列表生成式 ...

  6. python 中的列表解析和生成表达式 - 转

    优雅.清晰和务实都是python的核心价值观,如果想通过操作和处理一个序列(或其他的可迭代对象)来创建一个新的列表时可以使用列表解析(  List comprehensions)和生成表达式,通过这两 ...

  7. Python中的列表解析和生成表达式

    摘要:优雅.清晰和务实都是python的核心价值观,如果想通过操作和处理一个序列(或其他的可迭代对象)来创建一个新的列表时可以使用列表解析( List comprehensions)和生成表达式,通过 ...

  8. 3、Python迭代器、列表解析及生成器(0530)

    1.动态语言 sys.getrefcount()    //查看对象的引用计数 增加对象的引用计数场景 对象创建时:以赋值的方式,创建变量名的同时就会创建变量 将对象添加进容器时:类似list.app ...

  9. python基础之列表解析

    python列表解析:是一个让人欣喜的术语,你可以在一行使用一个for循环将所有的值放在一个列表之中.python列表解析属于python的迭代中的一种,相比python for循环速度会快很多. e ...

随机推荐

  1. 【BZOJ4403】序列统计(组合数学,卢卡斯定理)

    [BZOJ4403]序列统计(组合数学,卢卡斯定理) 题面 Description 给定三个正整数N.L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量.输出答案对10^6+3取 ...

  2. MyBatis相关配置

    在MyBatis中,不免会有一些配置要设置,我们先来看一下MyBatis配置XML文件的层次结构,这些层次是不能够颠倒顺序的,下面是层次结构: <?xml version = "1.0 ...

  3. MyBatis映射器元素

     映射器是MyBatis最强大的工具,也是我们使用MyBatis时用的最多的工具,映射器中主要有增删改查四大元素,来满足不同场景的需要: 下面是主要元素的介绍:         select:查询语句 ...

  4. 图之单源Dijkstra算法、带负权值最短路径算法

    1.图类基本组成 存储在邻接表中的基本项 /** * Represents an edge in the graph * */ class Edge implements Comparable< ...

  5. 微信小程序基于腾讯云对象存储的图片上传

    在使用腾讯云对象存储之前,公司一直使用的是传统的FTP的上传模式,而随着用户量的不断增加,FTP所暴露出来的问题也越来越多,1.传输效率低,上传速度慢.2.时常有上传其他文件来攻击服务器,安全上得不到 ...

  6. ubuntu,kali linux和windows三系统流水账——写给自己

    我先说一下ubuntu和windows双系统安装的几种方法,最后总结kali linux的安装,想起什么写什么,所以有点乱.然后记录一下自己的使用过程中遇见的问题和解决的方法,还有我的个人建议. 我个 ...

  7. 利用CVE-2017-11882拿到持久性shell

    利用CVE-2017-11882拿到持久性shell 近日微软又爆出一个严重漏洞,利用该漏洞可以直接拿到目标机shell.这么好玩的东西怎么能错过了,于是搭建环境复现了一把. 首先去GitHub上下载 ...

  8. Django+xadmin打造在线教育平台(二)

    三.xadmin后台管理 3.1.xadmin的安装 django2.0的安装(源码安装方式): https://github.com/sshwsfc/xadmin/tree/django2 把zip ...

  9. NGUI_Depth

    四.深度(Depth)概念; 1. (1).每一个UIPanel和每一个UI控件都一定会有一个Depth,深度值大代表显示的优先级高(会趋向于在界面更上层显示) (2).Depth决定的是UI的显示层 ...

  10. JS基础二

    JS的实现: 核心:ECMAScript ECMAScript 并不与任何具体浏览器相绑定,实际上,它也没有提到用于任何用户输入输出的方法(这点与 C 这类语言不同,它需要依赖外部的库来完成这类任务) ...