Reputation: 44465
I am interested in using one-line ternary expressions instead of traditional multiline if-else
blocks. However, expressions comparing is None
give different results.
Here is an example comparing multiline and one-line variants of two forms of a conditional expression for a predicate:
if pred is not None
if pred is None
Code
import operator as op
# First form
def is_not_none_multiline(a, b, pred=None):
if pred is not None:
predicate = pred
else:
predicate = lambda x, y: x + y
return predicate(a, b)
def is_not_none_oneline(a, b, pred=None):
predicate = pred if pred is not None else lambda x, y: x + y
return predicate(a, b)
# Second Form
def is_none_multiline(a, b, pred=None):
if pred is None:
predicate = lambda x, y: x + y
else:
predicate = pred
return predicate(a, b)
def is_none_oneline(a, b, pred=None):
predicate = lambda x, y: x + y if pred is None else pred
return predicate(a, b)
Tests
Here are tests for optional arguments in mutliline and one-line variants. The final result was unexpected:
assert is_not_none_multiline(1, 2) == 3
assert is_not_none_oneline(1, 2) == 3
assert is_not_none_multiline(1, 2, pred=op.mul) == 2
assert is_not_none_oneline(1, 2, pred=op.mul) == 2
assert is_none_multiline(1, 2) == 3
assert is_none_oneline(1, 2) == 3
assert is_none_multiline(1, 2, pred=op.mul) == 2
assert is_none_oneline(1, 2, pred=op.mul) == 2
# ----> 4 assert is_none_oneline(1, 2, pred=op.mul) == 2
# AssertionError:
Although pred is not None
works as one-line:
predicate = pred if pred is not None else lambda x, y: x + y
pred is None
does not work as one-line:
predicate = lambda x, y: x + y if pred is None else pred
Details
Apparantly, the pred
function is not evaluated when passed in as a keyword to is_none_oneline()
. Rather, it is returned:
print(is_none_oneline(1, 2, pred=op.mul))
# <built-in function mul>
This analysis was verified in a Python Tutor visualization when executing both variants of the second form (see visualizations here is not None
multiline, is not None
one-line, is None
multiline, is None
one-line).
Questions
It is unclear why an equivalent ternary expression returns a function rather than a computed value.
pred is None
expression?pred is None
in one-line?Upvotes: 2
Views: 844
Reputation: 362557
Just a simple case of operator precedence.
You're getting a callable which returns a callable. I think you wanted this instead, to make sure the conditional gets grouped the other way:
def is_none_oneline(a, b, pred=None):
predicate = (lambda x, y: x + y) if pred is None else pred
return predicate(a, b)
Upvotes: 3