```
>>> obj[**d] = "foo" # no kwd arguments provided here
```
I committed yesterday the following proposal
https://github.com/python/peps/pull/1622
But to be honest I am not sure if we should disallow these two constructs
```
d[*()]
d[**{}]
```
as equivalent to the disallowed `d[]` or allow them as equivalent to
`d[()]` (or whatever the sentinel will be)
I have thought extensively about this issue (in fact I lie awake thinking it through last night :-) and have come to some kind of resolution.
TL;DR: these should be allowed and use `d[()]` or whatever the sentinel will be, but I prefer the sentinel to be `()`.
But there are more cases than just the above two. Below I try to catch them all.
We've already established that in the absence of `*a` and keyword args, the index is a tuple when it looks like a tuple:
```
SYNTAX INDEX
d[x] x
d[x,] (x,)
d[x, y] (x, y)
```
We've also established that in the absence of `*a` but with at least one keyword arg, the index is a tuple unless there is exactly one index value:
```
SYNTAX INDEX KWARGS
d[x, k=z] x {"k": z}
d[x, y, k=z] (x, y) {"k": z}
```
I propose to treat `*a` in a similar fashion: If _after expansion of `*a`_ there is exactly one index value, the index is that value, otherwise it's a tuple. IOW:
```
SYNTAX INDEX
d[x, *[]] x
d[x, *[y]] (x, y)
d[*[], x] x
d[*[y], x] (y, x)
d[*[]] ()
d[*[x]] x
d[*[x, y]] (x, y)
```
Note that I use `*[...]` instead of `*(...)` -- since `*a` takes an arbitrary iterable, it doesn't matter whether `a` is a list, tuple, another type of sequence, or a general iterable (e.g. a set or dict, or a generator). I'm using `*[...]` consistently just to remind us of this fact (and to avoid having to type a trailing comma to create a singleton tuple).
We can easily extend this scheme to keyword args: As soon as either a keyword argument or `**kwargs` (or both) is present, we apply the same rule: If _after expansion of `*a`_ there is exactly one index value, the index is that value, otherwise it's a tuple. I'm not going to show all the cases, but here are some examples:
```
SYNTAX INDEX KWARGS
d[*[], k=z] () {"k": z}
d[*[x], k=z] x {"k": z}
d[*[x, y], k=z] (x, y) {"k": z}
d[*[], **{}] () {}
d[*[x], **{}] x {}
d[*[x, y], **{}] (x, y) {}
```
I propose to then treat the cases where there are no positional index values, only keywords (either `k=1` or `**{...}`, even `**{}`) _as if preceded by `*[]`_. So:
```
SYNTAX INDEX KWARGS
d[k=z] () {"k": z}
d[**{"k": z} () {"k": z}
d[**{}] () {}
```
The reason for these choices is to minimize the number of inconsistencies. We have a few unavoidable inconsistencies:
- if there's only one index value the index is not a tuple, in all other cases it's a tuple -- backward compatibility
- the special case for `d[x,]` (not the same as `d[x]`) -- also backward compatibility
- the difference between `d[x,]` (index is a tuple) and `d[x, k=1]` (index not a tuple) -- user expectations
There's also the special case for `d[k=1]`. Here our choices are to either forbid it syntactically or to provide a sentinel. I think forbidding it will prevent some reasonable use cases (e.g. tables with columns that have both positions and names). So I think it's best to use a sentinel. Using `()` as the sentinel reduces the number of special cases: the rule becomes "if there's exactly one positional value, use that value as the index; otherwise use a tuple", while with another sentinel the rule would become "if there's more than one positional value, use a tuple, if there's exactly one use that value, else (there are no positional values) use the sentinel". But if in the end people prefer a sentinel other than `()`, I can live with that -- in all the above cases, just replace `()` with the selected sentinel.
In both cases we also have an exception for the form `d[x,]`, but this factors out because it's the same complication in each case. Note that this exception is unique -- it only applies if the syntactic form has no keywords, no `**kwargs`, and no `*args`.
The introduction of `*args` requires us to decide what to do with the edge cases. I think the rule that best matches user expectations is to combine the plain positional values with the expansion of `*args`, take the resulting sequence of values, and _then_ apply the rule from the previous paragraph (using whichever sentinel we end up deciding on).
The introduction of `**kwargs` should pose no extra difficulties. Again, if there are no positional index values the sentinel index is used, and syntactic keywords are combined with `**kwargs` to form a single dict of keyword args. We end up finding that `d[**kwargs]` uses the index sentinel regardless of whether `kwargs` is empty or not. (If we were to end up forbidding `d[k=1]` syntactically, the only consistent choice would be to raise for `d[**{}]`, but I don't see a good reason to go this way.)
Note that `*args` and `**kwargs` both must combine the hard-coded arguments of the same nature (positional or keyword) with the dynamic ones before deciding. Anything else would lead to more rules and more inconsistencies.
Finally, in the above examples, `x`, `y` and `z`, when occurring in hard-coded arguments of either nature, may also be slices, e.g. `d[x]` could be `d[i:j]` or `d[i:j:k]` or e.g. `d[::]`. This makes no difference for the analysis. Note that in `*args` and `**kwargs` the slice notation is not syntactically valid -- but you can use explicit calls to `slice()`, e.g. `slice(i, j)`, `slice(i, j, k)` or `slice(None, None, None)`.
--