1-line idiom to replace if blocks

Bengt Richter bokr at oz.net
Tue Jan 21 04:50:51 EST 2003


On Tue, 21 Jan 2003 16:17:00 +0800, "Jonathan P." <jbperez808 at yahoo.com> wrote:

>**** Post for FREE via your newsreader at post.usenet.com ****
>
>I hate code that takes up too many lines and
>have come up with the ff. idiom to replace
>many 4 line if statements:
>
>result=[value-if-false,value-if-true][condition]
>
>This idea could also be applied as a compact
>switch block replacement in certain cases.

Sometimes you can use that, but the semantics really
are different from if/else. I.e., both value-if-xxx
expressions are always evaluated, whereas with an
if or (hacky version often required to be safe) shortcut
expression only one or the other is evaluated.

It doesn't matter for constants, but if it's a function with side
effects, like getting the next value from either of two different
iterators, then you see the difference. You can get the effect of if/else by

    result = [condition and [value-if-true] or [value-if-false]][0][0]

which uses short cut logic (and you have to reorder the terms). E.g.,

 >>> class It:
 ...     def __init__(self, v): self.v=v
 ...     def __iter__(self): return self
 ...     def next(self):  v = self.v; self.v=chr(ord(v)+1); return v
 ...
 >>> ita = It('a') ; itn = It('0')
 >>> for i in xrange(10): print [i%3==1 and [itn.next()] or [ita.next()]][0][0],
 ...
 a 0 b c 1 d e 2 f g

But using your idiom naively, both sequences count in tandem,
since both expressions are always evaluated:

 >>> ita = It('a') ; itn = It('0')
 >>> for i in xrange(10): print [ita.next(), itn.next()][i%3==1],
 ...
 a 1 c d 4 f g 7 i j

In this case it's easy to move the () to make it safe, but in general
you might not even know which term if any has a side effect even without
an obvious opportunity-hint of () at the end of the expression.

Regards,
Bengt Richter




More information about the Python-list mailing list