第四章:迭代器与生成器
文章目录
- 第一节:关于迭代器
- ==手动遍历迭代器==
- 使用 next() 进行迭代
- ==代理迭代==
- 使用__iter__ ()代理
- ==使用生成器创建新的迭代模式==
- ==反向迭代==
- 使用内置的 reversed() 进行返向迭代
- 在自定义类上实现 reversed ()
- ==迭代器切片==
- 使用 itertools.islice() 进行切片
- ==跳过可迭代对象的开始部分==
- 使用 itertools.dropwhile() 跳过
- 使用 itertools.islice() 跳过
- ==排列组合的迭代==
- 使用 itertools.permutations() 迭代遍历
- 使用 itertools.combinations() 迭代遍历
- 使用 tertools.combinations with replacement() 迭代遍历
- ==序列上索引值迭代==
- 使用 enumerate() 进行索引值迭代
- ==同时迭代多个序列==
- 使用 zip() 进行迭代
- 使用 itertools.zip longest() 进行迭代
- ==按顺序迭代多个序列==
- 使用 itertools.chain() 迭代
- ==创建数据处理管道==
- ==展开嵌套的序列==
- 使用包含 yield from 语句的递归生成器展开
- 使用 for 循环展开
第一节:关于迭代器
手动遍历迭代器
使用 next() 进行迭代
为了手动的遍历可迭代对象,使用 next() 函数并在代码中捕获 StopIteration 异
常。比如,下面的例子手动读取一个文件中的所有行:
例:
def manual_iter():with open('/etc/passwd') as f:try:while True:line = next(f)print(line, end='')except StopIteration:pass
代理迭代
使用__iter__ ()代理
__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)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)
使用生成器创建新的迭代模式
例:生产某个范围内浮点数的生成器
#定义一个方法,返回一个可迭代对象
def frange(start, stop, increment):x = startwhile x < stop:yield xx += increment#使用for遍历结果
for n in frange(0, 4, 0.5):
print(n)#或者使用list(),直接例表化
print(list(frange(0, 4, 0.5)))
一个函数中需要有一个 yield 语句即可将其转换为一个生成器。跟普通函数不同
的是,生成器只能用于迭代操作
一个生成器函数主要特征是它只会回应在迭代中使用到的 next 操作。
反向迭代
使用内置的 reversed() 进行返向迭代
例:
a = [1, 2, 3, 4]
for x in reversed(a):print(x)
'''
4
3
2
1
'''
【注意】当对象大小在可预见的情况,用此法,否则一定要转为列表才能使用
例:
f = open('somefile')
for line in reversed(list(f)):print(line, end='')
在自定义类上实现 reversed ()
例:
class Countdown():def __init__(self, start):self.start = start# Forward iteratordef __iter__(self):n = self.startwhile n > 0:yield nn -= 1def __reversed__(self):n = 1while n <= self.start:yield nn += 1
#从1遍历到30
for rr in reversed(Countdown(30)):print(rr)#从30遍历到1
for rr in Countdown(30):print(rr)
迭代器切片
使用 itertools.islice() 进行切片
例:
def count(n):while True:yield nn += 1
c = count(0)#普通切片方法,报错
print(c[10:20])#使用itertools.islice()import itertoolsfor x in itertools.islice(c, 10, 20):print(x)
'''
10
11
12
13
14
15
16
17
18
19
'''
迭代器和生成器不能使用标准的切片操作,因为它们的长度事先我们并不知道 (并且也没有实现索引)。函数 islice() 返回一个可以生成指定元素的迭代器,它通过遍历并丢弃直到切片开始索位置的所有元素。然后才开始一个个的返回元素,并直到切片结束索引位置。
跳过可迭代对象的开始部分
使用 itertools.dropwhile() 跳过
例:
#假定你在读取一个开始部分是几行注释的源文件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 dropwhilewith open('/etc/passwd') as f:for line in dropwhile(lambda line: line.startswith('#'), f):print(line, end='')
使用 itertools.islice() 跳过
如果你已经明确知道了要跳过的元素的个数的话,可以用此方法
例:
from itertools import islice#定义一个列表
items = ['a', 'b', 'c', 1, 4, 10, 15]#使用islice(),并遍历,指定从第3个元素到最后一个元素(即None)
for x in islice(items, 3, None):print(x)
'''
1
4
10
15
'''
在这个例子中, islice() 函数最后那个 None 参数指定了你要获取从第 3 个到最后的所有元素,如果 None 和 3 的位置对调,意思就是仅仅获取前三个元素恰恰相反,(这个跟切片的相反操作 [3:] 和 [:3] 原理是一样的)
排列组合的迭代
如何迭代遍历一个集合中元素的所有可能的排列或组合?
使用 itertools.permutations() 迭代遍历
例:
#定义一个列表
mlist = ['a', 'b', 'c']from itertools import permutationsfor i in permutations(mlist):print(i)
'''
('a', 'b', 'c')
('a', 'c', 'b')
('b', 'a', 'c')
('b', 'c', 'a')
('c', 'a', 'b')
('c', 'b', 'a')
'''#如果想得到指定长度的所有排列,还可以传递一个可选的长度参数for i in permutations(mlist,2):print(i)
'''
('a', 'b')
('a', 'c')
('b', 'a')
('b', 'c')
('c', 'a')
('c', 'b')
'''
使用 itertools.combinations() 迭代遍历
此方法可得到输入集合中元素的所有的组合,并且不介意顺序,如:(a,b)和(b,a)只会输出一个。
例:
mlist = ['a','b','c']from itertools import combinationsfor c in combinations(mlist, 2):print(c)'''
('a', 'b')
('a', 'c')
('b', 'c')
'''
使用 tertools.combinations with replacement() 迭代遍历
在计算组合的时候,一旦元素被选取就会从候选中剔除掉(比如如果元素’a’已经被选取了,那么接下来就不会再考虑它了)。而此函数允许同一个元素被选择多次
例:
from itertools import combinations_with_replacementmlist = ['a', 'b', 'c']for c in combinations_with_replacement(mlist, 3):print(c)
'''
('a', 'a', 'a')
('a', 'a', 'b')
('a', 'a', 'c')
('a', 'b', 'b')
('a', 'b', 'c')
('a', 'c', 'c')
('b', 'b', 'b')
('b', 'b', 'c')
('b', 'c', 'c')
('c', 'c', 'c')
'''
序列上索引值迭代
使用 enumerate() 进行索引值迭代
例:
mlist = ['a', 'b', 'c']for x, y in enumerate(mlist):print(x, y)# 遍历的元素带有序号,序号从“0”开始
'''
0 a
1 b
2 c
'''#想让序号从“1”开始,可以输入参数for x, y in enumerate(mlist,1):print(x, y)
'''
1 a
2 b
3 c
'''
该注意的地方:
有时候当你在一个已经解压后的元组序列上使用 enumerate() 函数时很容易调入陷阱
例:
data = [ (1, 2), (3, 4), (5, 6), (7, 8) ]# 正确的遍历方式
for n, (x, y) in enumerate(data):print(n,(x,y))
'''
0 (1, 2)
1 (3, 4)
2 (5, 6)
3 (7, 8)
'''# 错误的遍历方式
for n, x, y in enumerate(data):print(n,x,y)
同时迭代多个序列
使用 zip() 进行迭代
此法用于同时迭代多个序列,并且每次分别从一个序列中取一个元素,zip(a, b) 会生成一个可返回元组 (x, y) 的迭代器,其中 x 来自 a,y 来自 b。一旦其中某个序列到底结尾,迭代宣告结束。因此迭代长度跟参数中最短序列长度一致。
例:
mlist = [1,3,5,7,9]
ylist = [0,2,4,6,8,10]
for x,y in zip(ylist,mlist):print(x,y)
'''
0 1
2 3
4 5
6 7
8 9
'''
使用 itertools.zip longest() 进行迭代
例:
from itertools import zip_longestfor i in zip_longest(ylist,mlist):print(i)'''
(0, 1)
(2, 3)
(4, 5)
(6, 7)
(8, 9)
(10, None)
'''#如果想把None,用其他替换,可以用fillvalue参数
for i in zip_longest(ylist,mlist,fillvalue='empty'):print(i)
'''
(0, 1)
(2, 3)
(4, 5)
(6, 7)
(8, 9)
(10, 'empty')
'''
按顺序迭代多个序列
使用 itertools.chain() 迭代
例:
from itertools import chaina = [1, 2, 3, 4]
b = ['x', 'y', 'z']
for x in chain(a, b):print(x)
'''
1
2
3
4
x
y
z
'''
比对:itertools.chain() 要比先将序列合并再迭代要高效的多。
# 有效地执行遍历
for x in a + b:
...
# 更优的执行遍历
for x in chain(a, b):
创建数据处理管道
当有大量的数据需要处理,但是不能将它们一次性放入内存中时,生成器函数是一个实现管道机制的好办法
例:
#假如有个待处理的一个非常大的日志文件目录
foo/
access-log-012007.gz
access-log-022007.gz
access-log-032007.gz
...
access-log-012008
bar/
access-log-092007.bz2
...
access-log-022008#假设每个日志文件包含这样的数据:
124.115.6.12 - - [10/Jul/2012:00:18:50 -0500] "GET /robots.txt ..." 200 71
210.212.209.67 - - [10/Jul/2012:00:18:51 -0500] "GET /ply/ ..." 200 11875
210.212.209.67 - - [10/Jul/2012:00:18:51 -0500] "GET /favicon.ico ..." 404 369
61.135.216.105 - - [10/Jul/2012:00:20:04 -0500] "GET /blog/atom.xml ..." 304 -#为了处理这些文件,可以定义一个由多个执行特定任务独立任务的简单生成器函数组成的容器import bz2,gzip,os,re#找到匹配的目录中的所有文件名
def gen_find(filepat, top):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):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):for it in iterators:yield from it#在序列的序列中寻找正则表达式
def gen_grep(pattern, lines):pat = re.compile(pattern)for line in lines:if pat.search(line):yield line#现在可以很容易的将这些函数连起来创建一个处理管道。比如,为了查找包含单词 python 的所有日志行
lognames = 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)
展开嵌套的序列
#####将一个多层嵌套的序列展开成一个单层列表**
使用包含 yield from 语句的递归生成器展开
例:
from collections import Iterable#定义一个可迭代的生成器
def flatten(items, ignore_types=(str, bytes)):for x in items:#检查元素是否是可迭代if isinstance(x, Iterable) and not isinstance(x, ignore_types):yield from flatten(x)else:yield xitems = [1, 2, [3, 4, [5, 6], 7], 8]
print(flatten(items),type(flatten(items)))for x in flatten(items):print(x)'''
1
2
3
4
5
6
7
8
'''
使用 for 循环展开
例:
#定义一个可迭代的生成器
def flatten(items, ignore_types=(str, bytes)):for x in items:if isinstance(x, Iterable) and not isinstance(x, ignore_types):for i in flatten(x):yield ielse:yield x
第四章:迭代器与生成器相关推荐
- 第 十七 章迭代器、生成器和经典协程
当我在自己的程序中看到模式时,我认为这是一个麻烦的迹象.程序的形状应该只反映它需要解决的问题.代码中的任何其他规律性都表明,至少对我来说,我对抽象的理解还不够深--通常是我手动完成的事情,本应该通过写 ...
- Python(四)迭代器与生成器
1.手动遍历迭代器 遍历一个可迭代对象中的所有元素,但是却不想使用for循环 为了手动的遍历可迭代对象,使用 next() 函数并在代码中捕获 StopIteration 异常. 比如,下面的例子手动 ...
- 函数 (四) 迭代器和生成器
一 迭代器 一 迭代的概念 #迭代器即迭代的工具,那什么是迭代呢?#迭代是一个重复的过程,每次重复即一次迭代,并且每次迭代的结果都是下一次迭代的初始值 while True: #只是单纯地重复,因而不 ...
- python学习笔记分享(二十四)python学习笔记分期补充(二)复数,randint与sample,进制转换表,转义字符,二维数组,键,end,pass,迭代器和生成器
一:复数 Python支持复数,复数由实数部分和虚数部分构成,可以用a + bj,或者complex(a,b)表示, 复数的实部a和虚部b都是浮点型. complex(x) 将x转换到一个复数,实数部 ...
- 第14章可迭代的对象,迭代器和生成器
第14章可迭代的对象,迭代器和生成器 这一章大部分内容跟我之前写的一篇文章有重合 https://blog.csdn.net/qq_36267931/article/details/102954056 ...
- 流畅的python 14章可迭代的对象、迭代器 和生成器
可迭代的对象.迭代器和生成器 迭代是数据处理的基石.扫描内存中放不下的数据集时,我们要找到一种惰性获取数据项的方式,即按需一次获取一个数据项.这就是迭代器模式(Iterator pattern). 迭 ...
- python函数知识四 迭代器、生成器
15.迭代器:工具 1.可迭代对象: 官方声明,只要具有__iter__方法的就是可迭代对象 list,dict,str,set,tuple -- 可迭代对象,使用灵活 #方法一: list.__ ...
- python四大器_Python编程四大神兽:迭代器、生成器、闭包和装饰器
生成器 生成器是生成一个值的特殊函数,它具有这样一个特点:第一次执行该函数时,先从头按顺序执行,在碰到yield关键字时该函数会暂停执行该函数后续的代码,并且返回一个值:在下一次调用该函数执行时,程序 ...
- python可迭代对象 迭代器生成器_Python可迭代对象、迭代器和生成器
8.1 可迭代对象(Iterable) 大部分对象都是可迭代,只要实现了__iter__方法的对象就是可迭代的. __iter__方法会返回迭代器(iterator)本身,例如: >>&g ...
- Python精确指南——第四章-部署和技巧
4 Python工程打包部署 Python程序在提供给用户使用时,要脱离Python开发环境运行,此时,需要对python工程进行打包. 常用的Python打包工具有PyInstaller ...
最新文章
- 嵌入式开发板老化过程中显示温度与负载的关系脚本的用法
- iis 重新安装后 重新注册asp.net
- Boost.MultiIndex 复合键的例子
- Asp.Net Core(.net内核)
- PHP - windows下编译PHP 7.2的memcache
- python request处理_python requests异常处理
- 米莱狄机器人怎么那么多_王者荣耀米莱狄攻略,团战技能好了就丢,操作最简单上分法师...
- java生日正则表达式_Java语言十五讲
- 极简毕业设计答辩PPT模板
- python itchat_Python itchat模块在微信上的
- pom 备注_POM 500P的物性
- 计算机教师素养有哪些内容,现代教师应具备哪些教育技术能力
- Redis 中的 集合(Set)SREM:从集合中移除元素 忽略不存在的元素
- 用Python写一个植物大战僵尸
- 线上nacos命名空间误删如何找回 实践笔记
- UNREFERENCED_PARAMETER()宏函数
- Linux日志怎么分析
- python ——随机选取n个元素
- flink的Savepoint
- 推荐两个实用的PCIe工具软件