Python 处理对象上状态的Itertools/函数方法?

Python 处理对象上状态的Itertools/函数方法?,python,iteration,itertools,purely-functional,functools,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)

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

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)
使用()运行:

但是这种设计存在一些严重的问题,递归在Python中效率不高,并且正在创建一个列表并传递它的结果(它不是一个生成器)。尝试获取以下信息:

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

这很有效,但看起来有点可怕。。。是否有功能解决方案?

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

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]

如果您想保留状态,为什么不编写一个类,创建一个实例,然后在iterable上映射一个方法呢?然后,该方法可以在实例上存储它需要的任何状态。仅仅用函数来实现这一点似乎是不必要的限制。@BrenBarn这肯定是有原因的,因为OP标记了
纯函数性的
。你能提供一个简单的例子来说明你要做什么,或者至少解释一下你现有的例子应该实现什么吗?你的例子返回了一个东西的元组,但你根本没有解释它的用途。函数方法不是让你想要跟踪的值成为返回值的一部分,这样你就可以在另一个调用中使用它们:
return newit,seen_5,甚至seen
@Rightleg:是的,但我认为这一切都应该通过函数调用而不是显式递归来处理。所以是的,类似于
reduce
/
foldl
,但也许还有另一种方法@BrenBarn:我正在解决的当前问题是一个在单个迭代中运行的组合解析器/发射器。在
for
循环中求解非常简单,但我想知道是否有一个干净的函数解决方案。没错,这是一个干净的解决方案。嗯,今天早些时候我试着用
yield
,啊,我知道我做错了什么我将
yield
放在一个函数中,我调用该函数来循环
it
。显然这个解决方案会奏效,所以谢谢将暂时停止接受,想看看其他人有什么想法。-+1这是一个很好的解决方案,但它远不是纯粹的功能性解决方案。是的@Rightleg-最好的纯功能性解决方案将被接受为答案
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]