2003-02-07 12:03:31 -05:00
|
|
|
|
PEP: 308
|
|
|
|
|
Title: If-then-else expression
|
|
|
|
|
Version: $Revision$
|
|
|
|
|
Last-Modified: $Date$
|
|
|
|
|
Author: Guido van Rossum
|
|
|
|
|
Status: Active
|
|
|
|
|
Type: Standards Track
|
|
|
|
|
Content-Type: text/plain
|
|
|
|
|
Created: 7-Feb-2003
|
|
|
|
|
Post-History: 7-Feb-2003
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Introduction
|
|
|
|
|
|
|
|
|
|
Requests for an if-then-else ("ternary") expression keep coming up
|
|
|
|
|
on comp.lang.python. This PEP contains a concrete proposal of a
|
|
|
|
|
fairly Pythonic syntax. This is the community's one chance: if
|
|
|
|
|
this PEP is approved with a clear majority, it will be implemented
|
|
|
|
|
in Python 2.4. If not, the PEP will be augmented with a summary
|
|
|
|
|
of the reasons for rejection and the subject better not come up
|
|
|
|
|
again. While I am the author of this PEP, I am neither in favor
|
|
|
|
|
nor against this proposal; it is up to the community to decide.
|
|
|
|
|
If the community can't decide, I'll reject the PEP.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Proposal
|
|
|
|
|
|
|
|
|
|
The proposed syntax is as follows:
|
|
|
|
|
|
|
|
|
|
<expression1> if <condition> else <expression2>
|
|
|
|
|
|
|
|
|
|
This is evaluated like this:
|
|
|
|
|
|
|
|
|
|
- First, <condition> is evaluated.
|
|
|
|
|
|
|
|
|
|
- If <condition> is true, <expression1> is evaluated and is the
|
|
|
|
|
result of the whole thing.
|
|
|
|
|
|
|
|
|
|
- If <condition> is false, <expression2> is evaluated and is the
|
|
|
|
|
result of the whole thing.
|
|
|
|
|
|
|
|
|
|
Note that at most one of <expression1> and <expression2> is
|
|
|
|
|
evaluated. This is called a "shortcut expression"; it is similar
|
|
|
|
|
to the way the second operand of 'and' / 'or' is only evaluated if
|
|
|
|
|
the first operand is true / false.
|
|
|
|
|
|
|
|
|
|
To disambiguate this in the context of other operators, the
|
|
|
|
|
"if...else" part in the middle acts like a left-associative binary
|
|
|
|
|
operator with a priority lower than that of "or", and higher than
|
|
|
|
|
that of "lambda".
|
|
|
|
|
|
|
|
|
|
Examples of how this works out:
|
|
|
|
|
|
|
|
|
|
x if C else y if D else z <==> x if C else (y if D else z)
|
|
|
|
|
x or y if C else z <==> (x or y) if C else z
|
|
|
|
|
x if C else y or z <==> x if C else (y or z)
|
|
|
|
|
lambda: x if C else y <==> lambda: (x if C else y)
|
|
|
|
|
x if C else lambda: y <==> SyntaxError
|
|
|
|
|
x if C else y, z <==> (x if C else y), z
|
|
|
|
|
x, y if C else z <==> x, (y if C else z)
|
|
|
|
|
|
2003-02-07 19:56:13 -05:00
|
|
|
|
Note: a common way to emulate an if-then-else expression is:
|
|
|
|
|
|
|
|
|
|
<condition> and <expression1> or <expression2>
|
|
|
|
|
|
|
|
|
|
However, this doesn't work the same way: it returns <expression2>
|
|
|
|
|
when <expression1> is false! See FAQ 4.16 for alternatives that
|
|
|
|
|
work -- however, they are pretty ugly and require much more
|
|
|
|
|
effort to understand.
|
|
|
|
|
|
2003-02-07 12:03:31 -05:00
|
|
|
|
|
|
|
|
|
Alternatives
|
|
|
|
|
|
|
|
|
|
Many C-derived languages use this syntax:
|
|
|
|
|
|
|
|
|
|
<condition> ? <expression1> : <expression2>
|
|
|
|
|
|
2003-02-07 19:56:13 -05:00
|
|
|
|
Eric Raymond even implemented this. I reject this for several
|
|
|
|
|
reasons: the colon already has many uses in Python (even though it
|
|
|
|
|
would actually not be ambiguous, because the question mark
|
|
|
|
|
requires a matching colon); for people not used to C-derived
|
|
|
|
|
language, it is hard to understand.
|
2003-02-07 12:03:31 -05:00
|
|
|
|
|
2003-02-07 17:34:54 -05:00
|
|
|
|
---
|
2003-02-07 12:03:31 -05:00
|
|
|
|
|
2003-02-07 19:56:13 -05:00
|
|
|
|
David Ascher proposed a variant that doesn't have this problem:
|
2003-02-07 12:03:31 -05:00
|
|
|
|
|
|
|
|
|
<condition> ? <expression1> ! <expression2>
|
|
|
|
|
|
|
|
|
|
While cute, this suffers from the Perlish problem of using
|
|
|
|
|
arbitrary punctuation with an arbitrary meaning; and it's no
|
|
|
|
|
easier to understand than the ?: form.
|
|
|
|
|
|
2003-02-07 17:34:54 -05:00
|
|
|
|
---
|
2003-02-07 12:03:31 -05:00
|
|
|
|
|
|
|
|
|
If we could live with adding a new keyword, we could use:
|
|
|
|
|
|
|
|
|
|
if <condition> then <expression1> else <expression2>
|
|
|
|
|
|
|
|
|
|
Apart from the problem of introducing a new keyword for a minor
|
|
|
|
|
feature, this also suffers from ambiguity at the start of a
|
|
|
|
|
statement; for example:
|
|
|
|
|
|
|
|
|
|
if verbose then sys.stdout.write("hello\n") else None
|
|
|
|
|
|
|
|
|
|
could be an syntactically correct expression statement, but starts
|
|
|
|
|
with 'if', which makes the parser believe it is the start of an
|
|
|
|
|
'if' statement. To resolve this, the syntax would have to require
|
|
|
|
|
parentheses, which makes it uglier. However, this form has the
|
|
|
|
|
advantage of evaluating strictly from left to right (not that that
|
|
|
|
|
is a requirement for being Pythonic -- list comprehensions don't).
|
|
|
|
|
|
2003-02-07 17:34:54 -05:00
|
|
|
|
---
|
|
|
|
|
|
|
|
|
|
To deal with the problem of adding a new keyword, this variant has
|
|
|
|
|
been proposed:
|
|
|
|
|
|
|
|
|
|
if <condition> : <expression1> else <expression2>
|
|
|
|
|
|
|
|
|
|
This has the same ambiguity problem as the previous one (I would
|
|
|
|
|
even say more so), and lacks symmetry. It also begs the question
|
|
|
|
|
why there isn't a colon after the 'else'. But this:
|
|
|
|
|
|
|
|
|
|
if <condition> : <expression1> else: <expression2>
|
|
|
|
|
|
|
|
|
|
is even more confusing because it resembles the if statement so
|
|
|
|
|
much. (A solution that *doesn't* resemble the if statement is
|
|
|
|
|
better IMO since it should be obvious at first glance whether
|
|
|
|
|
we're dealing with an if expression or with an if statement.
|
|
|
|
|
Placing the 'if' in the middle somehow satisfies this
|
|
|
|
|
requirement.)
|
|
|
|
|
|
|
|
|
|
---
|
2003-02-07 17:13:53 -05:00
|
|
|
|
|
2003-02-07 15:18:45 -05:00
|
|
|
|
Many people suggest adding a new builtin instead of extending the
|
|
|
|
|
syntax of the language, e.g.:
|
|
|
|
|
|
|
|
|
|
ifelse(condition, expression1, expression2)
|
|
|
|
|
|
|
|
|
|
This won't work the way a syntax extension will because both
|
|
|
|
|
expression1 and expression2 must be evaluated before the function
|
|
|
|
|
is called. There's no way to short-circuit the expression
|
|
|
|
|
evaluation.
|
2003-02-07 12:03:31 -05:00
|
|
|
|
|
2003-02-07 17:29:39 -05:00
|
|
|
|
|
|
|
|
|
Variations
|
|
|
|
|
|
|
|
|
|
It has been proposed to make the 'else' part optional. This would
|
|
|
|
|
be a really bad idea. I showed:
|
|
|
|
|
|
|
|
|
|
x = e if C
|
|
|
|
|
|
2003-02-07 19:56:13 -05:00
|
|
|
|
to several people. They all thought that if C was false, it would
|
|
|
|
|
leave x unchanged. So don't even think about this one!
|
2003-02-07 17:29:39 -05:00
|
|
|
|
|
|
|
|
|
|
2003-02-07 12:03:31 -05:00
|
|
|
|
Copyright
|
|
|
|
|
|
|
|
|
|
This document has been placed in the public domain.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: indented-text
|
|
|
|
|
indent-tabs-mode: nil
|
|
|
|
|
sentence-end-double-space: t
|
|
|
|
|
fill-column: 70
|
|
|
|
|
End:
|