1.手动遍历迭代器

遍历一个可迭代对象中的所有元素,但是却不想使用for循环

为了手动的遍历可迭代对象,使用 next() 函数并在代码中捕获 StopIteration 异常。 比如,下面的例子手动读取一个文件中的所有行:

def manual_iter():with open('/etc/passwd') as f:try:while True:line = next(f)print(line, end='')except StopIteration:pass

StopIteration 用来指示迭代的结尾。 然而,如果你手动使用上面演示的 next() 函数的话,你还可以通过返回一个指定值来标记结尾,比如 None

with open('/etc/passwd') as f:while True:line = next(f, None)if line is None:breakprint(line, end='')

2.代理迭代

建了一个自定义容器对象,里面包含有列表、元组或其他可迭代对象。 你想直接在你的这个新容器对象上执行迭代操作。

只需要定义一个 __iter__() 方法,将迭代操作代理到容器内部的对象上去

class Node:def __init__(self, value):self._value = valueself._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)# Example
if __name__ == '__main__':root = Node(0)child1 = Node(1)child2 = Node(2)root.add_child(child1)root.add_child(child2)# Outputs Node(1), Node(2)for ch in root:print(ch)'''
Node(1)
Node(2)
'''

3.使用生成器创建新的迭代模式

def frange(start, stop, increment):x = startwhile x < stop:yield x #yield 语句即可将函数转换为一个生成器x += increment>>> for n in frange(0, 4, 0.5):
...     print(n)
...
0
0.5
1.0
1.5
2.0
2.5
3.0
3.5
>>> list(frange(0, 1, 0.125))
[0, 0.125, 0.25, 0.375, 0.5, 0.625, 0.75, 0.875]
>>>

一个生成器函数主要特征是它只会回应在迭代中使用到的 next 操作。 一旦生成器函数返回退出,迭代终止。

4. 实现迭代器协议

实现一个以深度优先方式遍历树形节点的生成器

class Node:def __init__(self, value):self._value = valueself._children = []def __repr__(self):return 'Node({!r})'.format(self._value)def add_child(self, node):self._children.append(node)
#Python的迭代协议要求一个 __iter__() 方法返回一个特殊的迭代器对象, 这个迭代器对象实现了 __next__() 方法并通过 StopIteration 异常标识迭代的完成def __iter__(self):return iter(self._children)def depth_first(self):#首先返回自己本身并迭代每一个子节点 从每一个节点找自己的子节点yield selffor c in self:yield from c.depth_first()# Example
if __name__ == '__main__':root = Node(0)child1 = Node(1)child2 = Node(2)root.add_child(child1)root.add_child(child2)child1.add_child(Node(3))child1.add_child(Node(4))child2.add_child(Node(5))for ch in root.depth_first():print(ch)# Outputs Node(0), Node(1), Node(3), Node(4), Node(2), Node(5)

5.反向迭代

反向迭代仅仅当对象的大小可预先确定或者对象实现了 __reversed__() 的特殊方法时才能生效

(1)对象为列表且大小已知

>>> a = [1, 2, 3, 4]
>>> for x in reversed(a):
...     print(x)
...
4
3
2
1

(2)如果两者都不符合,那你必须先将对象转换为一个列表才行

# Print a file backwards
f = open('somefile')
for line in reversed(list(f)):print(line, end='')

6.带有外部状态的生成器函数

关于生成器,很容易掉进函数无所不能的陷阱。 如果生成器函数需要跟你的程序其他部分打交道的话(比如暴露属性值,允许通过方法调用来控制等等), 可能会导致你的代码异常的复杂。 如果是这种情况的话,可以考虑使用上面介绍的定义类的方式。 在 __iter__() 方法中定义你的生成器不会改变你任何的算法逻辑。 由于它是类的一部分,所以允许你定义各种属性和方法来供用户使用。

from collections import dequeclass linehistory:def __init__(self, lines, histlen=3):self.lines = linesself.history = deque(maxlen=histlen)def __iter__(self):for lineno, line in enumerate(self.lines, 1):self.history.append((lineno, line))yield linedef clear(self):self.history.clear()

7.迭代器切片

函数 itertools.islice() 正好适用于在迭代器和生成器上做切片操作

>>> def count(n):
...     while True:
...         yield n
...         n += 1
...
>>> c = count(0)
>>> c[10:20]#迭代器和生成器不能使用标准的切片操作,因为它们的长度事先我们并不知道(并且也没有实现索引)。
Traceback (most recent call last):File "<stdin>", line 1, in <module>
TypeError: 'generator' object is not subscriptable>>> # Now using islice()
>>> import itertools
>>> for x in itertools.islice(c, 10, 20):#函数 islice() 返回一个可以生成指定元素的迭代器,它通过遍历并丢弃直到切片开始索引位置的所有元素。 然后才开始一个个的返回元素,并直到切片结束索引位置
...     print(x)
...
10
11
12
13
14
15
16
17
18
19
>>>

8.跳过可迭代对象的开始部分

(1)itertools.dropwhile() 函数 使用时,你给它传递一个函数对象和一个可迭代对象。 它会返回一个迭代器对象,丢弃原有序列中直到函数返回Flase之前的所有元素,然后返回后面所有元素

>>> with open('/etc/passwd') as f:
... for line in f:
...     print(line, end='')
...
##
# User Database
#
# Note that this file is consulted directly only when the system is running
# in single-user mode. At other times, this information is provided by
# Open Directory.
...
##
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
root:*:0:0:System Administrator:/var/root:/bin/sh
...
>>>>>> from itertools import dropwhile
>>> with open('/etc/passwd') as f:
'''
要么传入lambda的函数形式 要么进行判断筛选可迭代对象
lines = (line for line in f if not line.startswith('#'))for line in lines:
'''
...     for line in dropwhile(lambda line: not line.startswith('#'), f):
...         print(line, end='')
...
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
root:*:0:0:System Administrator:/var/root:/bin/sh
...
>>>

(2)已经明确知道了要跳过的元素的序号的话,那么可以使用 itertools.islice() 来代替

>>> from itertools import islice
>>> items = ['a', 'b', 'c', 1, 4, 10, 15]
>>> for x in islice(items, 3, None):
...     print(x)
...
4
10
15
>>>

9.排列组合的迭代

迭代遍历一个集合中元素的所有可能的排列或组合

(1)排列:itertools.permutations() , 它接受一个集合并产生一个元组序列,每个元组由集合中所有元素的一个可能排列组成

>>> items = ['a', 'b', 'c']
>>> from itertools import permutations
>>> for p in permutations(items):
...     print(p)
...
('a', 'b', 'c')
('a', 'c', 'b')
('b', 'a', 'c')
('b', 'c', 'a')
('c', 'a', 'b')
('c', 'b', 'a')
>>>#到指定长度的所有排列,你可以传递一个可选的长度参数
>>> for p in permutations(items, 2):
...     print(p)
...
('a', 'b')
('a', 'c')
('b', 'a')
('b', 'c')
('c', 'a')
('c', 'b')
>>>

(2)组合:使用 itertools.combinations() 可得到输入集合中元素的所有的组合

>>> from itertools import combinations
>>> for c in combinations(items, 3):
...     print(c)
...
('a', 'b', 'c')>>> for c in combinations(items, 2):
...     print(c)
...
('a', 'b')
('a', 'c')
('b', 'c')>>> for c in combinations(items, 1):
...     print(c)
...
('a',)
('b',)
('c',)
>>>

10.序列上索引值迭代

内置的 enumerate() 函数可以在迭代一个序列的同时获取到正在被迭代的元素索引

>>> my_list = ['a', 'b', 'c']
>>> for idx, val in enumerate(my_list):
...     print(idx, val)
...
0 a
1 b
2 c

应用:在你遍历文件时想在错误消息中使用行号定位

def parse_data(filename):with open(filename, 'rt') as f:for lineno, line in enumerate(f, 1):#行号从1开始fields = line.split()try:...except ValueError as e:print('Line {}: Parse error: {}'.format(lineno, e))

enumerate() 函数返回的是一个 enumerate 对象实例, 它是一个迭代器,返回连续的包含一个计数和一个值的元组, 元组中的值通过在传入序列上调用 next() 返回

11.同时迭代多个序列

目的:同时迭代多个序列,每次分别从一个序列中取一个元素

>>> xpts = [1, 5, 4, 2, 10, 7]
>>> ypts = [101, 78, 37, 15, 62, 99]
>>> for x, y in zip(xpts, ypts):
...     print(x,y)
...
1 101
5 78
4 37
2 15
10 62
7 99
>>>

zip(a, b) 会生成一个可返回元组 (x, y) 的迭代器,其中x来自a,y来自b。 一旦其中某个序列到底结尾,迭代宣告结束。 因此迭代长度跟参数中最短序列长度一致

如果想让迭代长度以最长的一致,需要自动填充补齐

>>> from itertools import zip_longest
>>> for i in zip_longest(a,b):
...     print(i)
...
(1, 'w')
(2, 'x')
(3, 'y')
(None, 'z')>>> for i in zip_longest(a, b, fillvalue=0):
...     print(i)
...
(1, 'w')
(2, 'x')
(3, 'y')
(0, 'z')
>>>

使用zip()可以让你将它们打包并生成一个字典

headers = ['name', 'shares', 'price']
values = ['ACME', 100, 490.1]s = dict(zip(headers,values))
print(s)'''
{'name': 'ACME', 'shares': 100, 'price': 490.1}
'''

12.不同集合上元素的迭代

想在多个对象执行相同的操作,但是这些对象在不同的容器中,希望代码在不失可读性的情况下避免写重复的循环

itertools.chain() 接受一个或多个可迭代对象作为输入参数。 然后创建一个迭代器,依次连续的返回每个可迭代对象中的元素。 这种方式要比先将序列合并再迭代要高效的多

>>> from itertools import chain
>>> a = [1, 2, 3, 4]
>>> b = ['x', 'y', 'z']
>>> for x in chain(a, b):
... print(x)
...
1
2
3
4
x
y
z
>>>

13.创建数据处理管道

以数据管道(类似Unix管道)的方式迭代处理数据。 比如,你有个大量的数据需要处理,但是不能将它们一次性放入内存中。

import os
import fnmatch
import gzip
import bz2
import redef gen_find(filepat, top):'''Find all filenames in a directory tree that match a shell wildcard pattern'''for path, dirlist, filelist in os.walk(top):for name in fnmatch.filter(filelist, filepat):yield os.path.join(path,name)def gen_opener(filenames):'''Open a sequence of filenames one at a time producing a file object.The file is closed immediately when proceeding to the next iteration.'''for filename in filenames:if filename.endswith('.gz'):f = gzip.open(filename, 'rt')elif filename.endswith('.bz2'):f = bz2.open(filename, 'rt')else:f = open(filename, 'rt')yield ff.close()def gen_concatenate(iterators):'''Chain a sequence of iterators together into a single sequence.'''for it in iterators:yield from itdef gen_grep(pattern, lines):'''Look for a regex pattern in a sequence of lines'''pat = re.compile(pattern)for line in lines:if pat.search(line):yield linelognames = gen_find('access-log*', 'www')
files = gen_opener(lognames)
lines = gen_concatenate(files)
pylines = gen_grep('(?i)python', lines)
for line in pylines:print(line)#为了查找包含单词python的所有日志行

14.展开嵌套的序列

将一个多层嵌套的序列展开成一个单层列表

from collections import Iterabledef flatten(items, ignore_types=(str, bytes)):for x in items:if isinstance(x, Iterable) and not isinstance(x, ignore_types):
#isinstance(x, Iterable)检查某个元素是否是可迭代的。 如果是的话, yield from 就会返回所有子例程的值
#额外的参数 ignore_types用来将字符串和字节排除在可迭代对象外,防止将它们再展开成单个的字符。yield from flatten(x)#在生成器中调用其他生成器作为子例程else:yield x>>> items = ['Dave', 'Paula', ['Thomas', 'Lewis']]
>>> for x in flatten(items):
...     print(x)
...
Dave
Paula
Thomas
Lewis
>>>

15.顺序迭代合并后的排序迭代对象

有一系列排序序列,想将它们合并后得到一个排序序列并在上面迭代遍历

>>> import heapq
>>> a = [1, 4, 7, 10]
>>> b = [2, 5, 6, 11]
>>> for c in heapq.merge(a, b):
...     print(c)
...
1
2
4
5
6
7
10
11

16.迭代器代替while无限循环

CHUNKSIZE = 8192def reader(s):while True:data = s.recv(CHUNKSIZE)if data == b'':breakprocess_data(data)#通常可以使用 iter() 来代替
def reader2(s):for chunk in iter(lambda: s.recv(CHUNKSIZE), b''):#它会创建一个迭代器, 这个迭代器会不断调用 callable 对象直到返回值和标记值相等为止,即data == b''时 break。pass# process_data(data)

Python(四)迭代器与生成器相关推荐

  1. python有关迭代器和生成器的面试题_【面试题 | Python中迭代器和生成器的区别?】- 环球网校...

    [摘要]今天给大家解答一道Python常见的面试题,希望这个面试栏目,给那些准备面试的同学,提供一点点帮助!小编会从最基础的面试题开始,每天一题.如果参考答案不够好,或者有错误的话,麻烦大家可以在留言 ...

  2. Python的迭代器和生成器

    Python的迭代器和生成器 一.迭代器Iterators 迭代器仅是一容器对象,它实现了迭代器协议.它有两个基本方法: 1)next方法 返回容器的下一个元素 2)__iter__方法 返回迭代器自 ...

  3. python函数知识四 迭代器、生成器

    15.迭代器:工具 1.可迭代对象: ​ 官方声明,只要具有__iter__方法的就是可迭代对象 list,dict,str,set,tuple -- 可迭代对象,使用灵活 #方法一: list.__ ...

  4. 第十六篇 Python之迭代器与生成器

    一.迭代器 一. 递归和迭代 生活实例说明什么是递归和迭代 A想去腾达大厦,问B怎么走路,B 说我不知道,我给你问问C,C也不知道,C又去问D,D知道,把路告诉了C,C又告诉B,B最后告诉A, 这就是 ...

  5. pythonfor循环遍历list_为什么for循环可以遍历list:Python中迭代器与生成器

    1 引言 只要你学了Python语言,就不会不知道for循环,也肯定用for循环来遍历一个列表(list),那为什么for循环可以遍历list,而不能遍历int类型对象呢?怎么让一个自定义的对象可遍历 ...

  6. Python之迭代器和生成器(Day17)

    一.可迭代对象(iterable) 刚才说过,很多容器都是可迭代对象,此外还有更多的对象同样也是可迭代对象,比如处于打开状态的files,sockets等等.但凡是可以返回一个迭代器的对象都可称之为可 ...

  7. python生成器单线程_【Python】迭代器、生成器、yield单线程异步并发实现详解

    转自http://blog.itpub.net/29018063/viewspace-2079767 大家在学习python开发时可能经常对迭代器.生成器.yield关键字用法有所疑惑,在这篇文章将从 ...

  8. Python之迭代器和生成器

    生成器和迭代器 提到生成器,总不可避免地要把迭代器拉出来对比着讲,生成器就是一个在行为上和迭代器非常类似的对象,如果把迭代器比作Android系统, 那么生成器就是ios,二者功能上差不多,但是生成器 ...

  9. python之迭代器,生成器

    一,迭代器 1.1什么是可迭代对象? 字符串.列表.元组.字典.集合都可以被for循环,说明他们都是可迭代的. 我们怎么来证明这一点呢? from collections import Iterabl ...

  10. python 生成式,迭代器,生成器

    DAY 6. 生成式,迭代器,生成器 6.1 生成式 6.1.1 列表生成式 list = [index for index in range(10)] 6.1.2 字典生成式 dict = {'zh ...

最新文章

  1. 重温目标检测--YOLO v2 -- YOLO9000
  2. 神策数据 VP 张涛:个性化推荐从入门到精通(附推荐产品经理修炼秘籍)
  3. 使用 husky 和 lint-staged 检查 Node.js 的代码一致性
  4. python游戏源码回合制游戏_python game源码下载
  5. 用ldd查看C++程序的依赖库
  6. HDU2564 词组缩写【文本】
  7. Eclipse下PHP开发 插件安装
  8. mysql 参数化分页_LR12 DataWizard从Mysql数据取参数化数据
  9. python3 gzip解压_使用 Python 解压缩 gzip 数据流
  10. Android9.0 PM机制系列(二)PackageInstaller安装APK
  11. Oracle,emc,emulex联合测试T10
  12. 根据项目或WBS结算规则批量生成下阶WBS的结算规则-CJB2
  13. 一个熟练程序员所具备的特质-2
  14. 【PTA】斐波那契数列第n项
  15. Maven项目自动更新/修复Javadoc
  16. selenium - web 自动化测试
  17. 药店管理系统源码 药店管理信息系统源码带文档
  18. c语言心得100,c语言实训心得精选范文
  19. 白杨SEO:谈谈我理解的营销,企业营销怎样做?
  20. 今日金融词汇---基本面分析

热门文章

  1. 苹果手机充电口接触不良怎么办_充电器接触不良怎么办 高手来教你几招-装修攻略...
  2. CAN控制器-配置过滤器
  3. 欧盟gmp中的计算机系统验证,欧盟GMP中的计算机系统验证.doc
  4. Linux 配置samba服务器
  5. 如何在网页中浏览和编辑DWG文件 梦想CAD控件 www.mxdraw.com
  6. 管家婆分销ERPV3A8单据第1行商品【】货位没有填写或不属于该仓库或已删除,不能保存
  7. [Win32]纯资源DLL
  8. 基于汇编语言实现打字练习软件
  9. 在Windows安装Ubuntu子系统
  10. html5上传steam,Steam 上的 HTML5 Javascript Game Engine