1

I have been going through a tutorial on lambda functions and came across this line of code to evaluate if a number is odd or even. And I do not understand how the tow logic operators work in this function.

(lambda x: (x % 2 and 'odd' or 'even'))(5)

'odd'

A more "usual/readable" way of doing it might be:

(lambda x: 'even' if x % 2 == 0 else 'odd')(3)

'odd'

I do understand that x % 2 will return either 1 or 0 (truthy or falsey) and based on that the ensuing logic will work. What I do not understand is how the output of x % 2 is then used in the body of the function and how it computes if it is 'odd' or 'even' that is returned. It might have something to do with the priority of Pythonic operators but so far it is not very clear. Any help will be much appreciated.

  • 3
    Note the definitions of `and` and `or` here: https://docs.python.org/3/library/stdtypes.html#boolean-operations-and-or-not – slothrop Aug 22 '23 at 09:31
  • 1
    `x or y` means "if x is true, then x, else y". `x and y` means "if x is false, then x, else y". From that, can you see how the lambda expression in the question works? – slothrop Aug 22 '23 at 09:31
  • 1
    For the first lambda function, you should take a look at truthy and falsy values. What happens when you use `and`, `or` with values beyond `True` or `False` see: https://stackoverflow.com/questions/47007680/how-do-and-and-or-act-with-non-boolean-values. The second line is a basic one line conditional. – MSH Aug 22 '23 at 09:32
  • this has nothing to do with lambda expressions, this is just how the `or` and `and` operators work. Note, lambda expressions aren't anything special - they add no real functionality, they are equivalent to `def _lambda(): return ` just that no name gets assigned to, and they are expressions, not statements – juanpa.arrivillaga Aug 22 '23 at 09:39
  • Anyway, this works due to precedence, since it is equivalent to ` (x % 2 and "odd") or "even"` and the way that `and`/`or` work (evaluating to one of it's operands). But note, this is potentially buggy, because of `"odd"` were soething falsey, e.g. the empty string, `""` this breaks, which is why you should use a conditional expression instead – juanpa.arrivillaga Aug 22 '23 at 09:47

2 Answers2

1

In Python every object can be tested for its boolean value - I highly recommend reading the linked Python official documentation section.
Python and and or operators not only evaluate the expression, but also return one of the operands based on the Boolen value:

  • and returns the second operand if the first evaluates to True; otherwise the first operand (evaluated to False) is returned.
>>> 1 and ''
''
>>> {} and True
{}
  • or returns the first operand if it evaluates to True; otherwise the second operand is returned.
>>> 'text' or True
'text'
>>> None or 0
0

In your lambda expression x % 2returns 1 for odd numbers, that in turn evaluates to Boolean True. Hence the first and operator returns the 'odd' string (first point in the list above), which becomes the first argument of the or operator. Because in Python non-empty strings are considered True, according to the second list point or returns this value ('odd') immediately.
By the same token, for even numbers x % 2 equates to 0 that is considered False in Python. So 0 is returned by the first and operator immediately, and then effectively discarded by the second or operator, which in turn returns its second operand, the 'even' string.

Take-home exercise: explain for the result of the following expression

(lambda x: (x % 2 and '' or 'even'))(5)

and why it is always the same regardless of the function argument, where the 'odd' string has been replaced with empty ''.

1

General Rule

In Python, conjunctions (stuff joined with 1 or more and) and disjunctions (or) evaluate to the last operand that needs to be evaluated to determine the truthiness of the whole expression. If there is no short-circuit operand, that is the last operand of the expression.

Conjunctions

For and, this determining operand is the first falsy operand (after which it is clear that the whole expression will falsy).

Disjunctions

For or, this determining operand is the first truthy operand (after which it is clear that the whole expression will truthy).

Your case:

The expression in your example is scoped:

(n % 2 and "odd") or "even"

Odd:

(1 and "odd") or "even"
# conj: both operands truthy, so the last one is taken
"odd" or "even"
# disj: first operand is truthy, so short-circuit
"odd"

Even:

(0 and "odd") or "even"
# conj: first operand is falsy, so short-circuit
0 or "even"
# disj: first operand falsy, so last operand is taken regardless of its value
"even"
user2390182
  • 72,016
  • 6
  • 67
  • 89