@h-vetinari
Back in June, I created a mini-draft PEP along these lines but shelved it, to my surprise this is now back in discussion would like to post excerpt from the beginning of it. Also provides a solution for placeholder empty tuple that can be easily extended without knowing trailing comma rules. This type of null unpacking doesn’t need to be represented in the AST.
This is presented as a generalized expansion of the concept, but can imagine reduced scope subset variants of the same idea:
- Limited to first literal element position in grammar to avoid confusion and potential typos of it being used later (would be no-op regardless). e.g.
(*,1) is valid, (1, *,) is invalid
- Omitting
{**} part, at expense of symmetry, because less useful than the * forms (especially sets and tuples)
- Limiting it to only the first element position in sets and tuples, at expense of more symmetry
- Scope reduced to the level of current proposal, special casing
{*} and not allowing {*,}, I believe this is the best way to disambiguate between dict/set semantics because of the existing {*iterable} and {**mapping} language behaviors, {,} is ambiguous between dict/set.
PEP: Null Literal Unpacking
Abstract
This PEP introduces a “null unpacking” syntax for list, tuple, set, and dictionary literals, allowing the use of bare * and ** operators with no expression to produce an empty literal of that type. These forms are:
| Literal Type |
Syntax |
Equivalent to |
| List |
[*] |
[] |
| Tuple |
(*,) |
() |
| Set |
{*} |
set() but faster since compiles to empty set opcodes |
| Dict |
{**} |
{} |
The feature adds symmetry between unpacking and literal syntax and provides an explicit, visually consistent way to represent empty literals in unpacking contexts. It also introduces a placeholder-friendly form for tuples that makes adding future elements simpler.
Motivation
Python already supports unpacking within literal displays:
[*a, *b] # list unpacking
(*a, *b) # tuple unpacking
{*a, *b} # set unpacking
{**x, **y} # dict unpacking
However, an empty unpacking ([*], {*}, (*,), {**}) is currently a SyntaxError. Null-unpack literals provide a consistent way to represent empty collections using familiar unpacking syntax, improving readability and consistency.
Placeholder-friendly tuples
Creating a tuple placeholder without elements currently requires working around trailing-comma rules. Null-unpack tuples allow:
coords = (*,) # empty tuple placeholder
coords = (*, 1) # easily extend later
coords = (*, 1, 2) # continue extending
This is consistent with Python’s tuple syntax and simplifies incremental construction.
Rationale
Consistency
Null-unpack literals complete the symmetry of PEP 448:
| Current valid |
Current invalid |
Proposed valid |
[*a] |
[*] |
[*] |
(*a,) |
(*,) |
(*,) |
{*a} |
{*} |
{*} |
{**a} |
{**} |
{**} |
Readability
It is immediately clear that a literal is empty or a placeholder.
Placeholder semantics
Supports positions in tuples for future expansion without requiring dummy values.
Performance
Null-unpack literals compile directly to the corresponding empty literal opcodes:
-
[ * ] → BUILD_LIST 0
-
{ * } → BUILD_SET 0
-
(* ,) → BUILD_TUPLE 0
-
{ ** } → BUILD_MAP 0
No runtime evaluation is needed.
AST Impact
-
Null-unpack literals do not create new AST nodes.
-
[ * ,] → List(elts=[], ctx=Load())
-
{ *, } → Set(elts=[], ctx=Load())
-
(* ,) → Tuple(elts=[], ctx=Load())
-
{ **, } → Dict(keys=[], values=[])
-
Starred nodes are omitted entirely.
This ensures AST reflects semantics, not source formatting. CST-based tools may still preserve the exact syntax.