Python does support if-else in lambdas...

7 points by globalrev ↗ HN
Just learned some tricks in #python in IRC-freenode:

I have heard a lot of complaints about Pythons lambdas being crippled but Python does allow if-else in lambdas, I didn't know before. Not in the ordinary Python way but:

f = lambda n_: (lambda ns: ns.__setitem__('f', lambda n: n if n in [0, 1] else \ fib(n-1) + fib(n - 2)) or ns['f'](n_))({})

map(lambda n: n3 if n % 2 == 1 else n2, range(10))

>>> reduce(lambda x,y: x+y if y % 2 == 1 else x-y, [1,2,3,4,5]) 3

>>> fib = lambda n: n if n in [0, 1] else fib(n-1) + fib(n - 2) >>> fib(12) 144

also: [n3 if n%2 else n2 for n in range(10)]

For soem reason * * disappears if next to each other.

9 comments

[ 3.4 ms ] story [ 34.3 ms ] thread
That's the normal python idiom for the ternary operator in other languages if I'm not mistaken. Its lambdas are still crippled, for the same reasons people called them crippled before, which is fine for python, IMO.

If I recall correctly, the if...else for ternary was added mainly because people were doing stuff with and...or to achieve the same effect.

I don't think there's anything wrong with the idiom

  condition and trueaction or falseaction
Am I behind the times? On a separate note, the code in the examples above is very difficult to read...a lambda really shouldn't be doing if/else operations like these in my opinion.
The formatting got messed up but yes I agree. They were just examples, not the best ones perhaps.

I have felt a need for it sometimes though. Very complicated lambdas are perhaps generally better off as normal functions.

But I hate creating one-time-use functions if it isn't necessary.

The problem with that construct is that trueaction itself must evaluate to true, or the expression will evaluate to falseaction, which most likely is not what you want:

  >>> 0 if 1 else 2
  0
  >>> 1 and 0 or 2
  2
Even crazier things can happen if trueaction has side effects:

  >>> def trueaction():
  ...     print 'trueaction called'
  ...     return 0
  ...
  >>> def falseaction():
  ...     print 'falseaction called'
  ...     return 'hello'
  ...
  >>> True and trueaction() or falseaction()
  trueaction called
  falseaction called
  'hello'
  >>> trueaction() if True else falseaction()
  trueaction called
  0
The danger here is that this will fall through to the falseaction if trueaction returns a false result ("", False, 0, None, [], {}, etc). For example, this will evaluate to "etc":

  True and "" or "etc"
So people started doing this instead, as [False] is still 'true' (non-empty lists are 'true' in Python):

  (condition and [trueaction] or [falseaction])[0]
... which is a bit crufty. So this was added:

  trueaction if condition else falseaction
Ah, that is much better. I've been learning from Dive Into Python which I know is a tad dated, and Pilgrim (sort of) endorses the and...or method.
Along with the points other people have made,

    trueaction if condition else falseaction
is marginally more clear than

    condition and trueaction or falseaction
, at least to people who aren't used to seeing and/or used like that. A lot of people, especially newer programmers, aren't used to seeing and...or used for branching that directly.
* * disappears because those are for italizicing text here. Obviously they should really only be hidden if they're surrounding something.
That's the way I write these if..else statements fib = lambda n: n in [0, 1] and n or fib(n-1) + fib(n - 2)