python推数据及流处理扩展

本文探讨了Python中处理流数据的方法,主要介绍了一个扩展,包括totrg(推数据版本的imap)、preduce(推数据版的reduce)和groupto(推数据版的groupby)。通过示例展示了如何实现从文件读取数据并输出到屏幕,以及进行分组求和操作。
摘要由CSDN通过智能技术生成

python对于“流”的处理以generator为主,这种方式适合拉数据,不适合推数据。

做个简单的扩展,totrg类似imap的推数据版本(可以一对一、一对多、一对零,完成类似imap、filter等功能),preduce类似reduce,groupto类似groupby的推数据版本。

fromsrc与rotrg对应,方便处理输入输出,fromto从输入读出发送到输出,支持标准输入输出、文件、list、generator,groupkv对groupby的扩展。

#
#coding:utf8
import sys
from itertools import imap,groupby

def coroutine(func):
    '''协程修饰器,调用一次被修饰的函数即可创建生成器,不用调用next函数'''
    def newfunc(*args,**kwargs):
        r = func(*args,**kwargs)
        r.next()
        return r
    return newfunc

def fromsrc(src,func=None,multi=False,fargs=()):
    '''从src读取,对接受的数据进行处理,之后作为生成器的数据,func为处理函数,
    multi表示是否func的输出为一对多'''
    if src == sys.stdin:
        for data in src:
            if func:
                if multi:
                    for d in func(*((data.rstrip('\r\n'),)+fargs)):
                        yield d
                else:
                    yield func(*((data.rstrip('\r\n'),)+fargs))
            else:
                yield data.rstrip('\r\n')
    elif type(src) == str:
        for data in open(src):
            if func:
                if multi:
                    for d in func(*((data.rstrip('\r\n'),)+fargs)):
                        yield d
                else:
                    yield func(*((data.rstrip('\r\n'),)+fargs))
            else:
                yield data.rstrip('\r\n')
    else:
        for data in src:
            if func:
                if multi:
                    for d in func(*((data,)+fargs)):
                        yield d
                else:
                    yield func(*((data,)+fargs))
            else:
                yield data

@coroutine
def totrg(trg,func=None,multi=False,fargs=()):
    '''对接受的数据进行处理,之后发送到trg,func为处理函数,
    multi表示是否func的输出为一对多'''
    if trg == sys.stdout or trg == sys.stderr:
        while True:
            data = yield
            if func:
                if multi:
                    for d in func(*((data,)+fargs)):
                        print >> trg, d
                else:
                    print >> trg, func(*((data,)+fargs))
            else:
                print >> trg, data
    elif type(trg) == str:
        with open(trg,'a') as t:
            while True:
                data = yield
                if func:
                    if multi:
                        for d in func(*((data,)+fargs)):
                            t.write(str(d)+'\n')
                    else:
                        t.write(str(func(*((data,)+fargs)))+'\n')
                else:
                    t.write(str(data)+'\n')
    elif type(trg) == list:
        while True:
            data = yield
            if func:
                if multi:
                    for d in func(*((data,)+fargs)):
                        trg.append(d)
                else:
                    trg.append(func(*((data,)+fargs)))
            else:
                trg.append(data)
    else:
        try:
            while True:
                data = yield
                if func:
                    if multi:
                        for d in func(*((data,)+fargs)):
                            trg.send(d)
                    else:
                        trg.send(func(*((data,)+fargs)))
                else:
                    trg.send(data)
        except StopIteration:
            stop(trg)
       
def stop(outstream):
    '''结束协程处理'''
    try:
        if outstream:
            outstream.throw(StopIteration)
    except StopIteration:
        pass

def fromto(src,trg,func=None,multi=False,fargs=()):
    '''从src读取数据,发送到trg,可用func对数据进行处理,
    multi表示是否func的输出为一对多'''
    t = totrg(trg)
    s = fromsrc(src)
    for data in s:
        if func:
            if multi:
                for d in func(*((data,)+fargs)):
                    t.send(d)
            else:
                t.send(func(*((data,)+fargs)))
        else:
            t.send(data)
    stop(trg)

@coroutine
def preduce(redfunc,outstream,init=None,finalfunc=None,initargs=()):
    '''把数据用redfunc汇总,可以用init初始化、finalfunc做结束操作,
    init可以是函数,也可以是值'''
    result = None
    if init != None:
        result = init(*initargs) if callable(init) else init
    try:
        while True:
            data = (yield)
            if result == None:
                result = data
            else:
                result = redfunc(result,data)
    except StopIteration:
        if finalfunc and callable(finalfunc):
            finalfunc(result)
        else:
            outstream.send(result)

def groupkv(instream,keyfunc=None,valuefunc=None):
    '''类似groupby函数,keyfunc对数据进行分组,valuefunc提取数据'''
    grp = groupby(instream,keyfunc)
    for k,vs in grp:
        yield k,imap(valuefunc,vs)

@coroutine
def groupto(outstream,grpfunc,keyfunc=None,valuefunc=None):
    '''类似groupby函数,数据处理采取推方式,
    用keyfunc对数据进行分组,有新分组时发送通知给outstream,
    同一组数据用grpfunc创建协程发送到该协程处理'''
    grpstream = None
    lastkey = None
    try:
        while True:
            data = (yield)
            key = keyfunc(data) if keyfunc else data
            value = valuefunc(data) if valuefunc else data
            if grpstream and key == lastkey:
                grpstream.send(value)
            else:
                stop(grpstream)
                grpstream = grpfunc(key)
                grpstream.send(value)
                outstream.send((key,grpstream))
                lastkey = key
    except StopIteration:
        stop(grpstream)

@coroutine
def null():
    '''丢到数据'''
    while True:
        yield

@coroutine
def groupsum(outstream,keyindex,valueindex):
    '''分组求和的例子'''
    def dealvalues(key):
        def sendresult(result):
            outstream.send((key,result))
        return preduce(int.__add__,null(),0,sendresult)
    grp = groupto(null(),dealvalues,itemgetter(keyindex),itemgetter(valueindex))
    try:
        while True:
            data = yield
            grp.send(data)
    except StopIteration:
        stop(grp)


transfer([1,2,3],'test.txt')          #从list复制到文件

transfer('test.txt',sys.stdout)   #从文件读输出到屏幕

分组求和:

keysums = []
grps = groupsum( totrg(keysums), 0, 1 )
fromto( [("a",1),("a",2),("b",3),("b",4),("c",5)], grps )

结果:[('a', 3), ('b', 7), ('c', 5)]


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值