5

What I found out:

In Dive in to Python I read about the peculiar nature of and and or operators and how shortcircuit evaluation of boolean operators may be used to express conditionals more succinctly via the and-or trick that works very much like the ternary operator in C.

C:

result = condition ? a : b

Python:

result = condition and a or b

This seems to come in handy since lambda functions are restricted to one-liners in Python, but it uses logical syntax to express control flow.

Since Python 2.5 the inline-if seems to have come to the rescue as a more readable syntax for the and-or trick:

result = a if condition else b

So I guess that this is the pythonic replacement for the less readable and-or-construct. Even if I want to nest multiple conditions, it still looks quite comprehensive:

result = a if condition1 else b if condition2 else c

But in a world of uncertainity I frequently find myself writing some code like this to access a.b.c :

result = a and hasattr(a, 'b') and hasattr(a.b, 'c') and a.b.c or None 

So with the help of inline-if I could probably get rid of some ands and ors, resulting in a quite readable piece of code:

result = a.b.c if hasattr(a, 'b') and hasattr(a.b, 'c') else None

I also discovered a somewhat arcane approach for conditonals in this recipe

result = (a, b)[condition] 

but this doesn't short-circuit and will result in all kinds of errors if the result of the condition does not return a boolean, 0 or 1.

What I'd like to know:

Now I wonder if it is considered preferable / more pythonic to use the inline-if as much as possible if downwards compatibility is not a concern, or is all just a matter of taste and how much one feels at home in the world of short-circuit evaluation?

Update

I just realized that inline-if is more than syntactic sugar for the and-or-trick, since it will not fail when a is false in a boolean context. So It's probably more fail-proof.

Bill the Lizard
  • 398,270
  • 210
  • 566
  • 880
codecraft
  • 1,163
  • 9
  • 11
  • In my opinion a large part of what is "pythonic" is readability, which is the easiest to read without having to think about what a line is doing? With that in mind I would suggest inline-if is the most pythonic as it can be read almost like English. – Stephen Paulger Feb 28 '11 at 13:26

4 Answers4

2

Since there is is a special language construct with the inline if-else that does what you want and which was introduced to replace ugly workarounds like those you mention, it is a good idea to use it. Especially since hacks like the and-or trick usually have unexpected corner cases/bugs.

The and-or trick for example fails in this case:

a = 0
b = 1
c = True and a or b

c will be 1, which is not what you expect if you are looking for if-else semantics.

So why use buggy workarounds when there is a language construct that does exactly what you want?

sth
  • 222,467
  • 53
  • 283
  • 367
2

The pythonic thing to do is recognise when you've stretched your code past what is sensible to cram into a single function and just use an ordinary function. Remember, there is nothing you can do with a lambda that couldn't also be done with a named function.

The breaking point will be different for everyone of course, but if you find yourself writing:

return a.b.c if hasattr(a, 'b') and hasattr(a.b, 'c') else None

too much, consider just doing this instead:

try:
     return a.b.c
except AttributeError:
     return None
Duncan
  • 92,073
  • 11
  • 122
  • 156
  • 1
    that makes a lot of sense. I often catch myself trying to maximize the amount of code that fits on a line, so I can oversee more code without scrolling... – codecraft Feb 28 '11 at 13:54
  • 1
    Actually I like the try/except solution -- it needs 4 lines but it is easy to understand what's happening, also you don't need to type attribute names redundantly. **But be aware** that if `b` or `c` are properties with non-trivial getter methods, the try/except construct might catch `AttributeError`s which actually are bugs! – Oben Sonne Feb 28 '11 at 13:57
0

I would rather be explicit about what my code is doing. Inline if is very explicitly doing conditional assignment and readability does count. Inline if would not have made it into the language if and/or side affects were considered preferable.

The pep for conditional expressions goes in to more detail about why that specific syntax was selected and it specifically discusses the and/or hack:

http://www.python.org/dev/peps/pep-0308/

stderr
  • 8,567
  • 1
  • 34
  • 50
  • I think this PEP was written & discussed before the advent of inline if, but there is a reference to Guido's motivation behind inline if (aka conditional expressions) http://mail.python.org/pipermail/python-dev/2005-September/056846.html – codecraft Feb 28 '11 at 13:44
0

This is for the particular case you mentioned, but I think that mostly every case in which you need chained short-circuit logic can be handled with a more elegant solution. Which is obviously a matter of taste, let me add, so scratch that if you think the above is better than this:

try:
    foo = a.b.c

except AttributeError:
    print "woops"

In other, less straightforward cases, encapsulating all the testing in a function might improve readibility a lot.

EDIT: by the way, duck typing.

salezica
  • 74,081
  • 25
  • 105
  • 166
  • Thanks! Could you recommend some sources of python code to study, so I get a feel for good and elegant coding? I have looked into the source code of django, but I found that parts of the code are abstracted to the max (using metaprogramming etc), so its often hard to tell from the code what's going on. – codecraft Feb 28 '11 at 14:00
  • 1
    The standard library itself (especially newer parts like collections, itertools, numbers, decimal). – ncoghlan Feb 28 '11 at 14:10