For review: PEP 308 - If-then-else expression

Andrew Dalke adalke at mindspring.com
Sat Feb 8 14:08:29 EST 2003


Andrew Koenig:
> To borrow an example from another thread, I consider
>
>   print n, "error" if n == 1 else "errors"
>
> to be more readable than
>
>   if n == 1:
>       print n, "error"
>   else:
>       print n, "errors"
>
> partly because there is only one flow of control so it is easy to see
> that n is printed in all cases.

Actually, I would have written this as

if n == 1:
  msg = "error"
else:
  msg = "errors"
print n, msg

so I could see that the n is always printed.

Or, using my function from the other thread,

print n, plural("error", n)

Hmmm, I thought of something else.  Consider this
code snippet

def buy(item, num_wanted):
  if num_wanted == 0:
    print "Sure, I'll give you nothing"
    return

  num_available = inventory[item]
  if num_available < num_wanted:
    if num_available == 0:
      print "We don't have any %ss in stock" % item
      return
    print "Looks like we only have %d %s" % (num_available,
                 item + "s" if num_available !=1 else item)
   num_wanted = num_available

 print "Shipping you %d of item %r" % (num_wanted, item)
 inventory[item] = inventory[item] - num_wanted

there is one use of the if/else expression here.  However, I
would argue that use is incorrect and it should be turned into
a function, because the code "the string to use for an amount
of a given item" is actually used twice.

    if num_available == 0:
      print "We don't have any %ss in stock" % item   <----- here
      return
    print "Looks like we only have %d %s" % (num_available,
                 item + "s" if num_available !=1 else item)  <---- here

Instead, it should be
def plural(item, n):
  if n == 1:
    return item
  return item + "s"
 ....
    if num_available == 0:
      print "We don't have any %s in stock" % plural(item, 0)
      return
    print "Looks like we only have %d %s" % (num_available,
                 plural(item, num_available)

and the use of if/else expression, which was done because it saved
a few lines, actually ended up obscuring the need for a function.


Consider also this

At the beginning there was

  buy(item, num_to_ship)

Then someone decided to ship an extra 5% to everyone who bought
more than 100 items.  Which is the prefered expression?

  # includes bonus buy
  buy(item, int(num_to_ship * 1.05) if num_to_ship > 100 else num_to_ship)
-or-
  if num_to_ship > 100:  # bonus buy
    num_to_ship = int(num_to_ship * 1.05)
 buy(item, num_to_ship)

How many people will choose the first of these options?  How
many would choose the second?  Is there any difficulty in understanding
one vs. the other?

I believe about 25% of the people will choose the embedded if/else
expression.  Some will do it because they can ("hey, this is a great time
to use this syntax") and others because it saves a couple lines and others
because it fits their brains.  Others, like me, will break it out because
odds are if this term is flexible then there will likely be other
modifications
in the future, while still others will do it because they didn't want to
deal with different ways of expressing the same thing (or didn't remember
that it exists.)

Then someone else requires there be a full-moon special, and
when the moon is > 98% full then everything must be doubled.
And the machine must play a howl sound effect.

The 25% who used the if/else expression may rewrite the code
as

 # bonus buy
  num_to_ship = int(num_to_ship * 1.05) if num_to_ship > 100 else
num_to_ship

 # werewolf special
  if moon_is_full():
    num_to_ship = num_to_ship * 2
    howl()

  buy(item, num_to_ship)

The first term was rewritten that way because it's an easy cut&paste
from the function call line.  That is appropriate because the fewer edits
done the fewer chances of mistakes.  However, the second term cannot
be written as an if/else expression (or should not -- replace "howl()" with
"print 'howl'" if you think otherwise).

So now there are two different if/else constructs for doing effectively
the same thing.  Compare that to using an if statement for both
branches

   if  num_to_ship > 100:
    num_to_ship = int(num_to_ship * 1.05) # bonus buy!

  if moon_is_full():
    num_to_ship = num_to_ship * 2  # werewolf special
    howl()

  buy(item, num_to_ship)



I am still against having an if/else expression.  I do agree there are
times when it can be useful and expressive.  However, I think more
times it will be used as alternative castings of the same code, and
I would rather there be one prefered form, and not two relatively
equal alternatives.  I believe that that will lead to code which is
generally more confusing than less.

I do understand that a good programmer will not abuse these
constructs even if they are there and prefers the more expressive
power.  However, I am also concerned about all the complicated
code I have to review and fix from people who are not good
programmers (nor claim to be) so don't know how to use these
tools well.

                    Andrew
                    dalke at dalkescientific.com






More information about the Python-list mailing list