迭代器与生成器04-按顺序迭代多个序列 / 创建数据处理管道 / 展开嵌套的序列

按顺序迭代多个序列

  • 使用 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
'''

比对: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 f
        f.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 x

items = [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 i
        else:
            yield x

猜你喜欢

转载自blog.csdn.net/xiangchi7/article/details/82601418