迭代器与生成器 (05)

时间:2020-07-01 00:13:50   收藏:0   阅读:45

这周不断优化和调试 sql, 经过精简和改逻辑, sql 也写了一千多行了, 这是数据处理部分, 然后这部分需要做调度 ETL, 生成宽表. 前台部分的 sql 也有几百行, 终于初步上线了, 剩下一些前台的样式慢慢调整, 感觉是接了一个大项目哇, 全部用sql来完成的, 感觉自己 sql 一下就突飞猛进了, 随心所欲地写, 过程中,不断要处理一些数据, 也是灵活用Python 安排上. Python + SQL 简直无敌, 在数据分析这块, 目前我是这样觉得.

然后, 还是抽空把剩下的一点点迭代器的内容, 赶紧来安排一下.

管道 (Pipeline) 方式处理数据

需求

想以类似 Linux 的方式, 迭代处理数据. 如处理一个很大的文件, 要分批, 不能够一次性读入内存中哦

方案

生成器函数 yield 安排上.

通常场景是多个路径下, 多个压缩文件夹, 下有多个文件, 各种乱七八糟格式的. 为了处理这些文件呢, 可以定义一个有多个执行任务的简单生成器函数的容器.

def gen_open(file_names): 
    """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 file_name in file_names:
        if file_name.endswith(‘.gz‘):
            f = gzip.open(file_name, ‘rt‘)
        
        elif file_name.endswith(‘.bz2‘):
            f = bz2.open(file_name, ‘rt‘)
    
        else:
            f = open(file_name, ‘rt‘)
        
        yield f 
        f.close()

def gen_concatenate(iterators): 
    """chain a sequence of iterators together into a sigle sequence"""
    for it in iterators:
        yield from it 
    
def gen_grep(pattern, lines):
    """look of a regex pattern in a sequence of lines"""
    pat  = re.compile(pattern)
    for line in lines:
        if pat.sreach(line):
            yield line 
    

虽然我平时不咋用这个, 但我总感觉迭代器这些东西蛮高级的, 比如 yield, 我现在写函数, 就优先会想, 能不能用 yield 来代替 return 等...

平铺 (Flatten) 嵌套序列

需求

要将一个多层嵌套的序列, 展开为一个单层列表. 这个就很常用了, 比如咱熟悉的 神经网络, 输入层就是要先将多维矩阵平铺为一个 1 维向量输入呀.

方案

用 yield from 语句, 写一个递归生成器来轻松实现.

#  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 
            
# test
items = [1, [2,2], [3,[4,[5,6,[5]]]]]
for i in flatten(items):
    print(i, end=‘,‘)
1,2,2,3,4,5,6,5,

这种骚操作, 我平时就会接触很多了. isinstance(x, Iterable) 用来检查某个元素是否为可迭代的. 如果是 True 的话, yield from 就会返回所有子例程的值. 即一个没有嵌套的简单序列.

参数 ignore_types 和检测语句 isinstance (x, ignore_types) 用来将字符串和字节排除在外, 防止再展开为单个字符.

words = [‘youge‘, [‘adore‘, ‘you‘], ‘at‘, [‘this‘,[‘time‘]]]
for word in flatten(words):
    print(word)
youge
adore
you
at
this
time

语句 yield from 在我们想在生成器中调用其他其他生成器,作为子例程的是否非常有用的. 它可以代替额外的 for 循环.

# if not use yield from 
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 

这样就会多写一个 for, 显然不如上者简洁和优雅. 还有就是, yield from 在涉及到, 基于微线程和生成器的并发编程中更有大作为, 后面抽空给补充上来.

评论(0
© 2014 mamicode.com 版权所有 京ICP备13008772号-2  联系我们:gaon5@hotmail.com
迷上了代码!