Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to express conditional execution inside Python lambdas?

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.

like image 459
codecraft Avatar asked Oct 11 '22 15:10

codecraft


2 Answers

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
like image 51
Duncan Avatar answered Nov 01 '22 10:11

Duncan


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?

like image 33
sth Avatar answered Nov 01 '22 10:11

sth