Itertools /处理状态超过对象的功能方法?

时间:2017-01-20 07:26:20

标签: python iteration itertools purely-functional functools

我的实际问题要大得多,但它的要点是:

def rec_func(it, newit, idx=0, seen_5=False, even_seen=0):
    num = next(it, None)
    if num is None:
       return newit
    elif num == 5: seen_5 = True
    elif num&1==0: even_seen +=1
    else: num*=20
    newit.append(num)
    print '[{}] seen_5 = {}, even_seen = {}'.format(idx, seen_5, even_seen)
    return rec_func(it, newit, idx+1, seen_5, even_seen)

使用(http://ideone.com/4kBbhn):

运行
a = []
rec_func(iter(xrange(10)), a)
print 'a =', a

但是这个设计存在一些严重的问题,递归在Python中效率不高,并且正在创建一个列表并仅仅为其结果(不是生成器)传递。试图得到这个:

a = tuple(itertools.<something>(func, iter(xrange(10)))
print a # same answer as before

我如何? - 我能想到的只有:

def func(num, state):
    if num == 5: state['seen_5'] = True
    elif num&1==0: state['even_seen'] +=1
    else: num*=20
    print '[?] seen_5 = {}, even_seen = {}'.format(state['seen_5'],
                                                   state['even_seen'])
    return num

_state = {'seen_5': False, 'even_seen': 0}
print tuple(imap(partial(func, state=_state), xrange(10)))

哪个有效,但看起来有点可怕......是否有功能性解决方案?

1 个答案:

答案 0 :(得分:1)

摆脱递归和中间列表的一种方法是使用生成器:

from __future__ import print_function


def gen(it):
    idx = 0
    seen_5 = False
    even_seen = 0
    for num in it:
        if num == 5: 
            seen_5 = True
        elif num&1==0: 
            even_seen +=1
        else: 
            num *= 20            
        print('[{}] seen_5 = {}, even_seen = {}'.format(idx, seen_5, even_seen))
        idx += 1
        yield num

print('a =', list(gen(iter(range(10)))))

输出:

[0] seen_5 = False, even_seen = 1
[1] seen_5 = False, even_seen = 1
[2] seen_5 = False, even_seen = 2
[3] seen_5 = False, even_seen = 2
[4] seen_5 = False, even_seen = 3
[5] seen_5 = True, even_seen = 3
[6] seen_5 = True, even_seen = 4
[7] seen_5 = True, even_seen = 4
[8] seen_5 = True, even_seen = 5
[9] seen_5 = True, even_seen = 5
a = [0, 20, 2, 60, 4, 5, 6, 140, 8, 180]