简体   繁体   中英

How to manage side effects in Python loops?

In many of my projects, I come across the following pattern of Python loops:

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)

Now if I want to abstract the handling of side effects, it gets complicated. For example, I want to print the first 10 items, then just dots and finally the last item:

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

Let's say I want to make this behavior generic for many loops. For this, I'm using a context manager around the loop, which is also called inside the loop to handle the side effects, like so:

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)

The printer keeps track of the iteration and can even act when the loop is done on __exit__ , thus can still update its status at this point

The problem I have with this is that it adds an indent for each loop where such a context manager is used, and the context manager is not tied to the loop. Do you have a better idea of solving this ?

You could create a wrapper for 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)

and use like this:

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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM