如何在Python循环中管理副作用?

时间:2018-03-08 15:22:45

标签: python iteration side-effects

在我的许多项目中,我遇到了以下Python循环模式:

for idx, item in enumerate(items):
    # apply and accumulate
    state = f(state, item)

    # display status/log something depending on state/item/iteration
    side_effect(idx, state, item)

现在,如果我想抽象出副作用的处理,那就变得复杂了。例如,我想打印前10个项目,然后只打印点,最后打印最后一个项目:

for idx, item in enumerate(items):
    # apply and accumulate
    state = f(state, item)

    # display status/log something depending on state/item/iteration
    if idx < 10:
        print(item)
    elif idx == 10:
        print('...')
if idx >= 10:
    print(item)
# in general, we cannot assume how many items there are, but
# it's a bit ugly imo because item is out of scope here
# if we solve this by keeping a reference to last item, it's worse imo

假设我想让这种行为在许多循环中都是通用的。为此,我在循环中使用了一个上下文管理器,它也在循环内部调用以处理副作用,如下所示:

with Printer(...) as printer:
    for idx, item in enumerate(items):
        # apply and accumulate
        state = f(state, item)

        # display status/log something depending on state/item/iteration
        printer.do_your_thang(item)

打印机会跟踪迭代,甚至可以在__exit__上完成循环时执行操作,因此此时仍可以更新其状态

我遇到的问题是它为使用这种上下文管理器的每个循环添加了一个缩进,并且上下文管理器没有绑定到循环。你有更好的解决方法吗?

1 个答案:

答案 0 :(得分:3)

您可以为enumerate

创建一个包装器
def printer(gen):
    for idx, item in gen:
        if idx < 10:
            print(item)
        elif idx == 10:
            print('...')
        yield idx, item
    if idx >= 10:
        print(item)

并使用如下:

for idx, item in printer(enumerate(items)):
    # apply and accumulate
    state = f(state, item)