I sometimes use generators to filter for certain values in programs and want to log the filtered items.
Let's assume:
def filter_items(items):
for item in items:
if item.is_wanted():
yield item
def process_items(items):
for item in filter_items(items):
item.do_stuff()
Now my problem is that I want to log, how many of the filtered items were actually invoked.
Currently I do this:
def process_items(items):
for count, item in enumerate(filter_items(items)):
item.do_stuff()
try:
count += 1
except UnboundLocalError:
count = 0
print('Processed', count, 'items.')
Now I have the feeling, that checking for an UnboundLocalError
is a bit weird, so I considered defaulting the counter instead:
def process_items(items):
count = -1
for count, item in enumerate(filter_items(items)):
item.do_stuff()
print('Processed', count + 1, 'items.')
However also setting the default counter to -1
also looks weird, since the actual default value on no iteration will be 0
. However I cannot default it to 0
because then I could not distinguish between the default value (if no element was iterated) or whether one element was iterated over.
Is there a best-practice or guideline regarding the defaulting of loop counters in Python?
I don't think a best practice exists. What I would do (in order to not initialize to -1
and then need to do count + 1
) is set the enumerate
's start
value to 1
:
def process_items(items):
count = 0
for count, item in enumerate(filter_items(items), start=1):
item.do_stuff()
print('Processed', count, 'items.')
this makes it clear to me what's going on. (Note that start=1
can just be written 1
).
Note that yes, this isn't the most explicit way to do this (see Stefan's answer). Since you do know about the fact that the for loop targets are visible after the loop, you should be ok.
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments