Ternary/Conditional Expressions

A place where you can post Python-related tutorials you made yourself, or links to tutorials made by others.

Ternary/Conditional Expressions

Postby Mekire » Thu Feb 21, 2013 11:10 am

If you have ever required a simple if/else statement in your code then conditional expressions might be of interest to you.

The standard if/else statement might look like this:
Code: Select all
if eggs:
    mystring = "Spam and eggs."
else:
    mystring = "Spam and spam."
I know that when I have to do such things I often lament that I needed four lines (or two if you put the statement on the same line as the colon) to do so.

In these cases one can use what is called a ternary or conditional expression (py2.5 and later according to documentation).
With this statement the previous code becomes:
Code: Select all
mystring = "Spam and eggs." if eggs else "Spam and spam."
This allows us to one-line our simple if/else statement.

Now I personally love this syntax, but it should obviously be used with some discretion. It is very easy to make an extremely long incomprehensible statement using this syntax. Apparently some Python programmers seem to think it should be avoided, but I tend to disagree. That said, I often default to it when there is a better alternative and have to catch myself. Essentially, be certain that it is actually making things easier when you use it; not more convoluted.

Now if you are comfortable with the syntax of such expressions, it is natural to ask if you can use it with the augmented assignment operators. The answer here is yes, but again, it is quite easy to make something that isn't particularly readable when doing so.

Here is an example:
Code: Select all
a += 1 if b%2 else 2
Now what exactly is this code saying?
It is telling us to increment the value of a by 1 if b is odd. If b is even, increment the value of a by 2. Is this the clearest way to write this statement? I don't know. If you are unsure if it is clear, don't use it. If you do decide to use the ternary expression with augmented assignment operators just be aware that the final value after the else will be evaluated using the same augmented assignment operator.

So our previous statement is equivalent to:
Code: Select all
if b%2:
    a+=1
else:
    a+=2


Notice also that our operator is only typed at the beginning of the ternary expression. If you write:
Code: Select all
a+=1 if b%2 else a+=2
while you may think that this is clearer, it won't work. When we use the ternary operator there are still two sides of the statement; The name to be assigned to, and the value (which in this case is conditional) being assigned. As this is the case, for clarity's sake I often find it is much clearer to write the statement as:
Code: Select all
a += (1 if b%2 else 2)
These parenthesis while not necessary, I find make the intention of the statement much clearer.

For more information on the subject here is the original PEP in which it was added: PEP 308
And for more on the ternary operator/expression in general see the wiki page: Ternary Operators ?:

If anyone has any additional thing to add on this subject, or foreboding warnings to programmers not to use it, please voice them. Also if you have any additional examples that you might feel are more illustrative of its uses please share them.

Cheers,
-Mek
(Edit: Slight edit for clarity; spaces added in the augmented assignment ternary example.)
Last edited by Mekire on Thu Feb 21, 2013 11:39 pm, edited 1 time in total.
User avatar
Mekire
 
Posts: 1025
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: Ternary/Conditional Expressions

Postby metulburr » Thu Feb 21, 2013 1:41 pm

Apparently some Python programmers seem to think it should be avoided

I am one of these programmers. One reason is when i scan code, and often miss an else/elif clause. I find the standard more structured, and noticeable. Now i like how python makes things condensed compared to other languages. But in some cases that feature turns into hinderance. This is also the reason i tend to stay away from list comps. I find it looks more cluttered. Even though its a little faster, i like the more readable standard approach. But thats just my option. Good post though!
New Users, Read This
OS Ubuntu 14.04, Arch Linux, Gentoo, Windows 7/8
https://github.com/metulburr
steam
User avatar
metulburr
 
Posts: 1512
Joined: Thu Feb 07, 2013 4:47 pm
Location: Elmira, NY

Re: Ternary/Conditional Expressions

Postby Mekire » Thu Feb 21, 2013 2:15 pm

Haha. Thankyou. I also love comprehensions. I think the time I spent doing some of the problems on Project Euler ruined me though. I like to try to turn complex algorithms into one-liners whenever possible. I will be the first to admit that at its worst this certainly doesn't aid readability and is far from Pythonic.

One thing I forgot to add. I find that placing parenthesis like so:
Code: Select all
a += (1 if b%2 else 2)
can massively improve the readability of such conditional statements (especially those with augmented assignment ops).

-Mek
User avatar
Mekire
 
Posts: 1025
Joined: Thu Feb 07, 2013 11:33 pm
Location: Amakusa, Japan

Re: Ternary/Conditional Expressions

Postby ichabod801 » Thu Feb 21, 2013 2:56 pm

A similar thing I sometimes do is use a boolean as an index for a len == 2 list. An example from this morning's bus ride:

Code: Select all
det = ['a', 'an'][words[1][0] in 'aeiouh']


instead of:

Code: Select all
if words[1][0] in 'aeiouh':
   det = 'an'
else:
   det = 'a'


Again, it is more concise but it hides the conditional that would otherwise be there.
Craig "Ichabod" O'Brien
Minimalist, buddhist, theist, and programmer
Current languages: Python, SAS, and C++
Previous serious languages: R, Java, VBA, Lisp, HyperTalk, BASIC
ichabod801
 
Posts: 84
Joined: Sat Feb 09, 2013 12:54 pm
Location: Outside Washington DC

Re: Ternary/Conditional Expressions

Postby micseydel » Thu Feb 21, 2013 6:03 pm

I do use the ternary operator, although I just looked at my code to give an example and when I was reading it I realized the code was incorrect... so I certainly can't defend it!

ichabod that's terrible! (I've done it before too, but I learned better! Especially since there's a ternary operator now, if you really wanted to do that).

Mekire, in your original post, I find the spacing (or lack thereof) in the first ternary example to be very confusing, as it implies that the += occurs or 2 does, rather than the += being applied to the whole right hand side.
Join the #python-forum IRC channel on irc.freenode.net!

Please do not PM members regarding questions which are meant to be discussed publicly. The point of the forum is so that others can benefit from it. We don't want to help you over PMs or emails.
User avatar
micseydel
 
Posts: 1443
Joined: Tue Feb 12, 2013 2:18 am
Location: Mountain View, CA

Re: Ternary/Conditional Expressions

Postby ichabod801 » Thu Feb 21, 2013 7:14 pm

micseydel wrote:ichabod that's terrible!


8-)

It just seems that choosing between two values for a single variable is a waste of a good conditional.
Craig "Ichabod" O'Brien
Minimalist, buddhist, theist, and programmer
Current languages: Python, SAS, and C++
Previous serious languages: R, Java, VBA, Lisp, HyperTalk, BASIC
ichabod801
 
Posts: 84
Joined: Sat Feb 09, 2013 12:54 pm
Location: Outside Washington DC

Re: Ternary/Conditional Expressions

Postby Somelauw » Sat Feb 23, 2013 12:17 am

The thing i don't like about ternaries in python is that it reads kinda backwards. I do like ternaries in other languages that use the ?:-syntax.

Lisp and scala do something neat because in those languages there is no difference between an if statements and an if-ternary.
You can just write:
Code: Select all
(let a (if (zero? (rem b 2)) 2 1) ...)

or
Code: Select all
val a = if (b % 2 == 0) {2} else {1}


Also, by the way, a feature that a future release of python could implement is a __call__-method in a boolean, such that one can do:
Code: Select all
a = (b % 2 == 0)(2, 1)


Lazy evaluation is still possible by using lambda's, so it becomes:
Code: Select all
a = (b % 2 == 0)(lambda: 2, lambda: 1)()


The closest syntax so far is:
Code: Select all
a = [lambda: 2, lambda: 1][b % 2]()

but that reads backwards
Join the #python-forum IRC channel on irc.freenode.net!
Somelauw
 
Posts: 73
Joined: Tue Feb 12, 2013 8:30 pm


Return to Tutorials

Who is online

Users browsing this forum: No registered users and 2 guests