conditional expressions

Alex Martelli aleax at
Mon Sep 30 11:09:08 EDT 2002

Terry Reedy wrote:
>> It's _dangerous_ -- to use it, one always has to be fully aware
>> of the risk that subexpression b might be false.
> If b is a non-null constant, there is no such risk.  Consider

If it's a constant, you don't need short-circuiting!

> na=1; np=3; nl=1; ng=0
> print "Found: %d apple%s, %d plum%s, %d lemon%s, and %d grape%s." %\
> (na, na!=1 and 's' or '', np, np!=1 and 's' or '', nl, nl!=1 and 's'
> or '', ng, ng!=1 and 's' or '')
> Found: 1 apple, 3 plums, 1 lemon, and 0 grapes.
> Alternatives to this 'risky' construct:

def plur(*ns):
    for n in ns:
        yield n
        yield 's'[n!=1:]

print "Found: %d apple%s, %d plum%s, %d lemon%s, and %d grape%s." % tuple(
    plur(na, np, nl, ng))

You can inline plur's logic if you want, of course -- although I
believe it's more readable in this way.  But anyway, the point is
that slicing is handier than and/or in this important special case.
For other cases in which you don't need short-circuiting, indexing
is fine -- " ('ba','glor')[n!=1] " if that's what a certain natural
language wants for singular/plural endings.  But when one accepts
that a function for such pluralization is preferable anyway, then
if-else becomes attractive once again:

def plur(*ns, singular=_(''), plural=_('s')):
    for n in ns:
        yield n
        if n == 1: yield singular
        else: yield plural

I've shown this i18n'd with gettext's convention _( ... ) , but
of course not all languages can pluralize by a constant suffix
(English can't -- if ever a number of leaves or fishes was
among the found things, we'd be in trouble...!-), so a better
approach might be, e.g., for English:

def plur(*numbers_and_nouns):
    for i in range(len(numbers_and_nouns)):
        number, noun = numbers_and_nouns[i:i+2]
        yield "%d %s" % (number, pluralize(number, noun))


plural_exceptions = {'man':'men', 'child':'children', # etc etc
        'leaf':'leafes', 'fish':'fishes',             # etc etc
def pluralize(number, noun):
    if number == 1:
        return noun
        return plural_exceptions.get(noun, noun+'s')

You could factor this up in different ways, but please DO ensure
your software never output "plurals" such as "mans", "childs",
"leafs", or "fishs".

> 1. forgo the nicety of correct English output

That's basically what you're doing when you choose to just
conditionally append s's.  If you do take such a shortcut
(because you know that none of the nouns you handle can ever
be one of the many exceptions in English pluralization),
then slicing is one option -- but overall I prefer a short
function to wrap the pluralization task, I think that the
ability to give the function a name helps clarity a LOT,
whether you ARE willing to "just stick an s at the end" OR
waht to ensure "the nicety of correct English output".

> 2. nest if/else four levels deep to choose correct variant of 16 print
> statements (ugh)
> 3. precalculate 4 suffixes and store in 4 temp vars with 4 if/else's
> (8 or 16 lines);
>    though clearly superiour to 2), this is still tedious with some
> risk of typo error.

"Risk of typo error" is quite present even in your repetition of
the and/or idiom (and to a lesser extent in a similarly inlined
repetition of the slicing or indexing idioms).  Better to wrap
things into a function: NO repeated code...!


More information about the Python-list mailing list