how to avoid checking the same condition repeatedly ?

Steven D'Aprano steve+comp.lang.python at pearwood.info
Mon Oct 28 07:14:08 EDT 2013


On Mon, 28 Oct 2013 09:50:19 +0000, Wolfgang Maier wrote:

> Dear all,
> this is a recurring programming problem that I'm just not sure how to
> solve optimally, so I thought I'd ask for your advice: imagine you have
> a flag set somewhere earlier in your code, e.g.,
> 
> needs_processing = True
> 
> then in a for loop you're processing the elements of an iterable, but
> the kind of processing depends on the flag, e.g.,:
> 
> for elem in iterable:
>     if needs_processing:
>         pre_process(elem)  # reformat elem in place
>     print(elem)
> 
> this checks the condition every time through the for loop, even though
> there is no chance for needs_processing to change inside the loop, which
> does not look very efficient. 

If there is absolutely no chance the flag could change, then the best way 
is to test the flag once:

> if needs_processing:
>     for elem in iterable:
>         pre_process(elem)  # reformat elem in place 
>         print(elem)
> else:
>     for elem in iterable:
>         print(elem)


The amount of duplication here is trivial. Sometimes you can avoid even 
that:

if needs_preprocessing:
    preprocess(sequence)
process(sequence)


This is especially useful if you can set up a pipeline of generators:


if flag1:
    data = (preprocess(item) for item in data)
if flag2:
    data = (process(item) for item in data)
if flag3:
    data = (postprocess(item) for item in data)
for item in data:
    print(item)



Another option is to use a factory-function:

def factory(flag):
    def process(item):
        do_this(item)
        do_that(item)
        do_something_else(item)
        print(item)
    if flag:
        def func(item):
            preprocess(item)
            process(item)
        return func
    else:
        return process



func = factory(needs_preprocessing)
for elem in iterable:
    func(elem)




> So my question is: is there an agreed-upon generally best way of dealing
> with this?

No. It's mostly a matter of taste. Those coming from a Java background 
will probably prefer the factory or builder idiom. Those coming from a 
functional language background, like Haskell or Lisp, or with experience 
with Unix pipes, will probably prefer using chained generators.

The only solution you absolutely should avoid is the naive "copy and 
paste" solution, where the amount of code duplication is extensive:


if needs_preprocessing:
    for elem in iterable:
        # If you change this block, you must remember to change the 
        # block below too!
        preprocess(item)
        do_this(item)
        do_that(item)
        do_something_else(item, arg1, arg2, expression)
        do_another_thing(item + arg3, key=whatever)
        print(item)
else:
    for elem in iterable:
        # If you change this block, you must remember to change the 
        # block above too!
        preprocess(item)
        do_this(item)
        do_that(item)
        do_something_else(item, arg1, arg2, expression)
        do_another_thing(item, key=whatever)
        print(item)


The careful reader will notice that there's already a bug in this.


Even checking the variable inside the loop is okay, provided you don't 
care too much about performance, although I wouldn't call it "best 
practice". Merely "acceptable for code that isn't performance-critical".


-- 
Steven



More information about the Python-list mailing list