views:

613

answers:

6

I have this

bc = 'off'

if c.page == 'blog':
    bc = 'on'

print bc

Is there a more pythonic (and/or shorter) way of writing this in python?

+19  A: 

Shortest one should be:

bc = 'on' if c.page=='blog' else 'off'

Generally this might look a bit confusing, so you should only use it when it is clear what it means. Don't use it for big boolean clauses, since it begins to look ugly fast.

freiksenet
That's ok for software using Python 2.5 and greater
iElectric
<2.5 compatibility was not mentioned in question ;)
freiksenet
Still worth mentioning.
Triptych
I'll have to argue about the "shortest" claim (see my answer for a shorter one).
scrible
Shortest readable :)
freiksenet
This is the shortest not necessarily more Pythonic, I asked a similar questions months ago: http://stackoverflow.com/questions/331767/python-style
OscarRyz
+9  A: 

Or you could use an inline if statement:

>>> cpage = 'blog'
>>> bc = 'on' if cpage == 'blog' else 'off'
>>> bc
'on'
>>> cpage = 'asdf'
>>> bc = 'on' if cpage == 'blog' else 'off'
>>> bc
'off'

There's a bit of a writeup on that feature at this blog, and the relevant PEP is PEP308. The inline if statement was introduced in Python 2.5.

This one might be a little less pythonic, but you can use and/or in this fashion:

>>> cpage = 'asdf'
>>> bc = (cpage == 'blog') and 'on' or 'off'
>>> bc
'off'
>>> cpage = 'blog'
>>> bc = (cpage == 'blog') and 'on' or 'off'
>>> bc
'on'

This one is used more often in lambda statements than on a line by itself, but the form

 A and B or C

is similar to

   if A:
       return B
   else:
       return C

I was going to write out a little bit longer explanation, but they covered it better at Dive into Python. They also noted a couple caveats that you probably need to know.

Mark Rushakoff
Second one looks *really* confusing. Can you please expand answer to explain why it works like this?
freiksenet
Thanks for explanation. It still is very unreadable for me. I think first option is better.
freiksenet
The second option is what people used before we got the first one, on those occasions when cramming things io one line was more important than readability..
John Fouhy
That second one surely gets a low score for readability. Not Pythonic.
Craig McQueen
The and/or approach *used* to be the Pythonic way of doing a conditional in a lambda, until PEP308. See the first two paragraphs of the PEP: http://www.python.org/dev/peps/pep-0308/
Mark Rushakoff
+16  A: 

Well, not being a python guy please take this with a huge grain of salt, but having written (and, with more difficulty, read) a lot of clever code over the years, I find myself with a strong preference now for readable code. I got the gist of what your original code was doing even though I'm a nobody as a Python guy. To be sure, you could hide it and maybe impress a Python wonk or two, but why?

John Lockwood
I agree entirely. Write for readability!
Gary Willoughby
C people use i++. Pythonic if can be used as shorthand for obvious conditionals as i++ or i+= can be used as shorthand for obvious operations.
freiksenet
@freiksenet: I think a better comparison is using the ?: statements in other languages for short, simple -- inline -- conditionals. And, arguably, those can make the code more readable rather than cluttering it up with extra lines that add no functionality.
lilbyrdie
Just FYI, "Pythonic" is a term that promotes readability over terseness.
TM
+13  A: 

This is:

  1. definitely shorter
  2. arguably Pythonic (pre-Python 2.5, which introduced the controversial X if Z else Y syntax)
  3. questionably readable. With those caveats in mind, here it goes:

    bc = ("off","on")[c.page=="blog"]
    

EDIT: As per request, the generalized form is:

   result = (on_false, on_true)[condition]

Explanation: condition can be anything that evaluates to a Boolean. It is then treated as an integer since it is used to index the tuple: False == 0, True == 1, which then selects the right item from the tuple.

scrible
Fascinating. As with another one above, could you generalize that a bit more and explain it? (As in ... you weren't kidding about #3).
lilbyrdie
`("off", "on")` is a tuple and `c.page=="blog"` evaluates to the index of the element that is being accessed
Otto Allmendinger
I wanted to vote down because it's really ugly, then I remembered that I used it myself.
kaizer.se
This is what I use when 2.5 isn't available; I find ‘and...or’ unacceptable as it reads weirdly and fails if the and-value is something that isn't truthy. The drawback of ‘(a, b)[cond]’ is that both a and b are evaluated, so you can't rely on shortcutting, which means you can't convert a construct like “'nothing' if item is None else item.name”.
bobince
+1  A: 

you can use "a = b if c else d" but if you are using a python version prior to 2.5

bc = c.page == "blog" and "on" or "off"

can do the trick also.

M. Utku ALTINKAYA
A: 

Another possibility is to use a dict if you can compute the values outside of the function that accesses them (i.e. the values are static, which also addresses the evaluation issue in scrible's answer's comments).

want_bc = {True: "on", False: "off"}

...

bc = want_bc[c.page == "blog"]

I prefer this and/or the tuple indexing solutions under the general rubric of preferring computation to testing.