1

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

2 Answers 2

2

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)
Sign up to request clarification or add additional context in comments.

1 Comment

Thanks. I will make a strong mental note never to go light on the bracketing again.
0

What happens here, is python takes your ternary expression, as the first item to be unpacked and , None as the second. Same thing with brackets:

a, b = (foo() if not condition else None), None

This can be mitigated by doing:

a, b = foo() if not condition else (None, None)

Which will give you the correct result:

>>> a, b = foo() if not condition else (None, None)
>>> a, b
([1, 2], 3)

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.