r/Python • • 5d ago

Meta Consistency of new unpacking syntax in 3.15?

Not sure if this question belongs here or if the flair is right, but I have a question.

You can now (3.15 and up, PEP 448) unpack nested lists and dictionaries with * and ** in comprehension expressions, for example:

>>> ranges = [range(i) for i in range(5)]
>>> [*item for item in ranges]
[0, 0, 1, 0, 1, 2, 0, 1, 2, 3]

(Code from PEP)

but I also try to do small checks and this doesn't seem possible:

>>> [b for b in [*a if min(a)<2 else *(a[::-1]) for a in [(1, 2), (3, 4)]] if b%2==0]
  File "<python-input-4>", line 1
    [b for b in [*a if min(a)<2 else *(a[::-1]) for a in [(1, 2), (3, 4)]] if b%2==0]
                                     ^
SyntaxError: cannot unpack only part of a conditional expression

I need junky work around:

[c for c in [*b for b in [a if min(a)<2 else (a[::-1]) for a in [(1, 2, 3), (4, 5, 6)]]] if c%2==0]
[2, 6, 4]

And also having an outside list due to the fact that there is no option to filter the elements the stars unpacks. Any chances this improves with future versions?

Update: thanks for the responses everyone, I think u/latkde explains it very well in their post. Yes in practice I think I can't use this kind of syntax for a while now and be it just get compatibility with older versions, it would be just for my own side projects and quick checks answering math questions online. I was just curios because needing to put an expression in parentheses is not something I am very used to in Python (and try to avoid if I can) and since the previous versions seemed to have relaxed the rules in this regard (or was it just help, exit and quit?) I didn't understand why the expression above wouldn't work.

19 Upvotes

32 comments sorted by

View all comments

Show parent comments

12

u/latkde Tuple unpacking gone wrong 5d ago

The unpacking is part of the generator syntax. Unpacking does not create a new value category, so it cannot be used within conditionals.

Formally, we are in an “flexible expression” context. Unpacking (a starred expression) can only occur in a flexible expression. The elements of an expression list (such as the contents of a […] literal can be expressions, as can be the value expression in a … for … in … generator expression. So you can say *some_expression for … in …, but not *some_expression if … else *other_expression – the conditional expression syntax doesn't allow flexible expressions there.

That means we can say [*(… if … else …) for … in …] but not [*… if … else *… for … in …].