码迷,mamicode.com
首页 > 其他好文 > 详细

迭代器与生成器 (05)

时间:2020-07-01 00:13:50      阅读:45      评论:0      收藏:0      [点我收藏+]

标签:ignore   就会   this   分析   linu   单个字符   for 循环   com   没有   

这周不断优化和调试 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 在涉及到, 基于微线程和生成器的并发编程中更有大作为, 后面抽空给补充上来.

迭代器与生成器 (05)

标签:ignore   就会   this   分析   linu   单个字符   for 循环   com   没有   

原文地址:https://www.cnblogs.com/chenjieyouge/p/13216851.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!