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.