Python 进阶_迭代器 & 列表解析
目录
迭代器
迭代器是一个含有 next() 方法的对象,让我们可以迭代不是序列数据类型但表现出序列行为的对象,所以可以说迭代器为类序列对象提供了一个类序列的接口(只要是实现了 __iter__() 方法的对象,就可以使用迭代器来进行访问)。迭代器从对象的第一个元素开始访问,直到所有的元素被遍历后结束。对于无法通过索引计数来随机访问元素的数据结构(EG. set)而言,迭代器是唯一的访问其自身元素的方式。
NOTE1: 但迭代器是不支持索引计数的,所以迭代器不能回退,只能往前进行迭代。
NOTE2: 迭代器也不是线程安全的,在多线程环境中对可变对象使用迭代器是一个危险的操作。所以一般情况下应该坚持对不可变对象实现迭代器。
NOTE3: 迭代器对象不支持被多次迭代
In [19]: a = ListIter([1,2,3,4,5])
In [20]: [i for i in a]
Out[20]: [1, 2, 3, 4, 5]
In [21]: [i for i in a]
Out[21]: []
In [22]:
iter() :内建的迭代器生成函数
iter(…)
iter(collection) -> iterator
iter(callable, sentinel) -> iterator
Get an iterator from an object. In the first form, the argument must
supply its own iterator, or be a sequence.
In the second form, the callable is called until it returns the sentinel.
1. 如果传递了一个序列(sequence)实参,迭代器会从索引 0 一直迭代至结束。
2. 如果传递了两个实参 EG. iter(func, sentinel),迭代器会重复的调用 func 直到迭代器的下一个值为 sentinel 。
EXAMPLE 1:
In [44]: aList = ['jmilkfan', 'fanguiju', 'chocolate']
In [45]: aIter = iter(aList)
In [46]: aIter.next()
Out[46]: 'jmilkfan'
In [47]: aIter.next()
Out[47]: 'fanguiju'
In [48]: next(aIter)
Out[48]: 'chocolate'
In [49]: aIter.next()
---------------------------------------------------------------------------
StopIteration Traceback (most recent call last)
<ipython-input-49-5ab62b0e2847> in <module>()
----> 1 aIter.next()
StopIteration:
迭代器通过其内建的 iter.next() 方法,或通过 Python 内建的 next() 来迭代下一个元素,直到最后触发 StopIteration 异常后表示迭代结束。
EXAMPLE 2: 捕获异常
In [56]: aList = ['jmilkfan', 'fanguiju', 'chocolate']
In [57]: aIter = iter(aList)
In [58]: while True:
...: try:
...: print aIter.next()
...: except StopIteration:
...: print 'Done'
...: break
...:
jmilkfan
fanguiju
chocolate
Done
迭代器在 for 循环中
EXAMPLE 3: 对 EXAMPLE 2 的改进
In [59]: aList = ['jmilkfan', 'fanguiju', 'chocolate']
In [60]: aIter = iter(aList)
In [61]: for x in aIter:
...: print x
...:
jmilkfan
fanguiju
chocolate
Python 在 for 循环的语法糖中,让 for 循环能够自动的调用迭代器的 next() 方法以及捕获 StopIteration 异常。
迭代器与字典
字典是一个可迭代对象,其迭代器会变量它的 key, 所以我们可以应用这个特性将语句 for eachKey in myDict.keys() 改进为 for eachKey in myDict
EXAMPLE 4:
In [62]: aDict = {'name':'jmilkfan', 'sex':'man'}
In [69]: for x in aDict:
...: print ''.join([x,': ',aDict[x]])
...:
name: jmilkfan
sex: man
迭代器与文件
文件也是一个可迭代对象,迭代器会自动的调用文件对象的 readline() 方法,所以可以将语句 for eachLine in myFile.readlines() 修改为 for eachLine in myFile
EXAMPLE 5:
myFile = open('FILENAME')
for eachLine in myFile:
print eachLine
myFile.close()
创建迭代器对象
EXAMPLE 6: 一个斐波那契数列
class Fab(object):
def __init__(self, max):
self.max = max
self.n, self.a, self.b = 0, 0, 1
def __iter__(self):
return self
def next(self):
if self.n < self.max:
r = self.b
self.a, self.b = self.b, self.a + self.b
self.n = self.n + 1
return r
raise StopIteration()
if __name__ == '__main__':
fab = Fab(5)
print fab
for x in fab:
print x
Output:
In [79]: run demo_1.py
<__main__.Fab object at 0x00000000047CDE80>
1
1
2
3
5
将实例化语句 fab = Fab(5) 修改成 fab = Fab(100) 后执行,再看看 Output:
1
.
.
.
354224848179261915075
NOTE: 这一类的应用场景会对内存造成非常大的负担,建议使用迭代器来减少内存的压力。
EXAMPLE 6 中的 __iter__() 方法 return 了自己,所以迭代的对象就是自身。除此之外,我们还可以实现 委托迭代。
创建迭代对象并实现委托迭代
委托迭代:就是将迭代请求委托到迭代对象内部持有的容器对象上。它能让自己创建的新容器能够完成迭代操作。
EXAMPLE 7:
class Node:
def __init__(self, value):
self._value = value
self._children = [] # 迭代对象所持有的容器对象
def __repr__(self):
return 'Node({!r})'.format(self._value)
def add_child(self, node):
self._children.append(node)
def __iter__(self):
return iter(self._children) # 将迭代请求转发给迭代对象内部所持有的容器对象
if __name__ == '__main__':
root = Node(0)
child1 = Node(1)
child2 = Node(2)
root.add_child(child1)
root.add_child(child2)
for ch in root: # 调用 Node:__iter__()
print(ch) # 调用 Node:__repr__()
Output:
Node(1)
Node(2)
EXAMPLE 7 是一个树结构,执行自身(root),返回子节点(Node(1)、Node(2)) 。这个例子,当我们 for 循环遍历迭代器对象 root 时,实际上是迭代了 self._children = [Node(1), Node(2)],这就是迭代委托。
迭代器的多次迭代
在上文写到,迭代器不支持被多次迭代,这样实在不能说是灵活。为了解决这一个问题,引入了可迭代对象(iterables)和迭代器对象(iterator)两个不同的概念。
- 迭代器对象:
__iter__()返回的是迭代器对象自身。 - 可迭代对象:
__iter__()返回了一个迭代器对象。
上述的 委托迭代 就是一个返回一个迭代器对象的例子,所以 EXAMPLE 7 是一个 可迭代对象,他能够被多次迭代。
In [1]: run demo_1.py
Node(1)
Node(2)
In [2]: run demo_1.py
Node(1)
Node(2)
列表解析
是一个非常有用、简单且灵活的工具,让我们能够动态的创建列表类型对象。
语法:
[expr for iter_variable in iterable]
EXAMPLE 1:
In [18]: [x**2 for x in range(10)]
Out[18]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
In [80]: map(lambda x:x ** 2, range(10))
Out[80]: [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]
上面两条语句的效果是一样的,但列表解析的方法仅调用一次 range(10), 而第二条则调用了 map()/lambda/range(10),这说明列表解析可以替代 map() 以及 lambda ,以此来获取更高的效率。
列表解析的样例
- 嵌套 for 循环实现的矩阵
In [81]: [(x+1, y+1) for x in range(3) for y in range(5)]
Out[81]:
[(1, 1),
(1, 2),
(1, 3),
(1, 4),
(1, 5),
(2, 1),
(2, 2),
(2, 3),
(2, 4),
(2, 5),
(3, 1),
(3, 2),
(3, 3),
(3, 4),
(3, 5)]
- 统计文件单词数
f = opem('FILENAME', 'r')
len([word for line in f for word in line.split()])
- 求素数
[x for x in range(2,100) if not [y for y in range(2,int(x/2+1)) if x % y == 0]]
- 嵌套列表降维
In [143]: nestLi = [[1,2,3],[4,5,6],[7,8,9]]
In [144]: newLi = [x for para in nestLi for x in para]
In [145]: newLi
Out[145]: [1, 2, 3, 4, 5, 6, 7, 8, 9]
列表解析和迭代器
因为 for 循环的关系,所以从上面的例子可以看出列表解析和迭代器之间的关系非常紧密。深入的理解两者,对提高 Python 程序的效率有非常大的帮助。迭代是 Python 一个非常重要的思想和特性。
Python 进阶_迭代器 & 列表解析的更多相关文章
- Python 进阶_生成器 & 生成器表达式
目录 目录 相关知识点 生成器 生成器 fab 的执行过程 生成器和迭代器的区别 生成器的优势 加强的生成器特性 生成器表达式 生成器表达式样例 小结 相关知识点 Python 进阶_迭代器 & ...
- python利用or在列表解析中调用多个函数.py
python利用or在列表解析中调用多个函数.py """ python利用or在列表解析中调用多个函数.py 2016年3月15日 05:08:42 codegay & ...
- python进阶_浅谈面向对象进阶
python进阶_浅谈面向对象进阶 学了面向对象三大特性继承,多态,封装.今天我们看看面向对象的一些进阶内容,反射和一些类的内置函数. 一.isinstance和issubclass class F ...
- Python入门笔记(13):列表解析
一.列表解析 列表解析来自函数式编程语言(haskell),语法如下: [expr for iter_var in iterable] [expr for iter_var in iterable i ...
- Python进阶:迭代器与迭代器切片
2018-12-31 更新声明:切片系列文章本是分三篇写成,现已合并成一篇.合并后,修正了一些严重的错误(如自定义序列切片的部分),还对行文结构与章节衔接做了大量改动.原系列的单篇就不删除了,毕竟也是 ...
- Python基础:08列表解析与生成器表达式
一:列表解析 列表解析(List comprehensions)来自函数式编程语言Haskell .它可以用来动态地创建列表.它在 Python 2.0 中被加入. 列表解析的语法: [exp ...
- Python进阶-V 迭代器(Iterator)、生成器(Generator)函数
一.迭代器 1.可循环的有哪些,即可用for语句或者while语句的数据类型有哪些? 字符串(str).列表(list).元组(tuple).字典(dic).集合(set).枚举类(enumerate ...
- Python 进阶_模块 & 包
目录 目录 模块的搜索路径和路径搜索 搜索路径 命名空间和变量作用域的比较 变量名的查找覆盖 导入模块 import 语句 from-import 语句 扩展的 import 语句 as 自动载入模块 ...
- python 进阶篇 迭代器和生成器深入理解
列表/元组/字典/集合都是容器.对于容器,可以很直观地想象成多个元素在一起的单元:而不同容器的区别,正是在于内部数据结构的实现方法. 所有的容器都是可迭代的(iterable).另外字符串也可以被迭代 ...
随机推荐
- app自动化appium使用内置adb命令
一.Appium-server使用 1.登陆页面 高级设置:可以设置Android 和 IOS 日志级别:dabug非常详尽的日志 记录python代码向他发送的请求以及他在收到请求后做的一系列处理 ...
- 希希敬敬对Alpha阶段测试报告
已经完成的功能:1 GUI界面效果已经达到了设计要求,经过review代码完成度较好,GUI.PY代码可以使用,完成了“贴吧名字关键字与URL关联”. 2 能够实现"贴吧名字关键字与URL关 ...
- Jenkins搭建,节点配置
一.服务器安装jdk和Jenkins 二.安装完成后打开jenkins页面:http://localhost:8080,设置管理员密码后登陆进去. 三.系统管理->全局变量,勾选允许用户注册 ...
- 《JAVA设计模式》之迭代器模式(Iterator)
在阎宏博士的<JAVA与模式>一书中开头是这样描述迭代子(Iterator)模式的: 迭代子模式又叫游标(Cursor)模式,是对象的行为模式.迭代子模式可以顺序地访问一个聚集中的元素而不 ...
- 深入理解DiscoveryClient
Spring Cloud Commons 提供的抽象 最早的时候服务发现注册都是通过DiscoveryClient来实现的,随着版本变迁把DiscoveryClient服务注册抽离出来变成了Servi ...
- 【五一qbxt】day5 图论
图论 学好图论的基础: 必须意识到图论hendanteng xuehuifangqi(雾 图 G = (V,E) 一般来说,图的存储难度主要在记录边的信息 无向图的存储中,只需要将一条无向边拆成两条即 ...
- 问题 1436: 地宫取宝 (dp)
题目传送门 时间限制: 1Sec 内存限制: 128MB 提交: 423 解决: 94 题目描述 X 国王有一个地宫宝库.是 n x m 个格子的矩阵.每个格子放一件宝贝.每个宝贝贴着价值标 ...
- call和apply,函数伴侣
Predefined:js中的this指向直接运行上下文. call和apply是ECMASCRIPT 3在函数原型上所定义的方法,目的在于改变或指定this的指向,从而改变函数直接执行上下文.两者的 ...
- 基于6U VPX的 SRIO 接口, 和PCIe 接口的msata 固态存储卡
基于6U VPX 的mSATA高性能数据存储板 一.板卡概述 该产品系我司自主研发.基于标准6U VPX架构. 二.产品特性 最大存储容量8TB 读写方式RAID0 ...
- 英伟达GPU 嵌入式开发平台
英伟达GPU 嵌入式开发平台 1. JETSON TX1 开发者组件 JETSON TX1 开发者组件是视觉计算的全功能 开发平台,旨在让您能够快速地安装和运行. 该组件带有 Lin ...