I have noticed an odd problem with unpacking multiple values in a ternary expression. Firstly, a MWE illustrating the syntax, in which the intent is to unpack the tuple on the right and assign the list inside it to the first name on the left, and the number to the second name.
condition = False
a, b = [1, 2], 3 if not condition else None, None # ValueError: too many values to unpack
def foo():
return [1, 2], 3
([1, 2], 3) == foo() # True
a, b = foo() # works as expected: a = [1, 2] and b = 3
a, b = foo() if not condition else None, None # now a = ([1, 2], 3) and b is None
My question is to understand the rationale behind the syntax here. If condition
evaluates as false, why would the last part of the ternary expression, the else
clause, ever be evaluated at all? Is Python assigning the second None
to b
? This makes no sense to me, but I cannot see how else a) no ValueError is raised to tell me that unpacking has not worked at all (if my syntax somehow compels Python to treat the whole tuple as a single entity rather than unpacking it) and b) a value is nonetheless assigned to b
. The obvious next tests:
a, b = foo() if not condition else None, 'test' # Now a = ([1, 2], 3) and b = 'test'
a, b = (lambda x: [[1, 2], 3])('blah') if not condition else None, 'test' # Same result with a lambda function.
So it seems that the else clause is being evaluated. Why does this happen? Is there an elegant way of rewriting this to allow me to call the function inside such a ternary expression, aside from the obvious and arguably clumsier
if not condition:
a, b = foo()
else:
a, b = None, None
This is just precedence. Python is parsing this as:
a, b = (foo() if not condition else None), None
For your expected result, you'll need to add parentheses around the Nones:
a, b = foo() if not condition else (None, None)