On Sun, 2020-08-16 at 12:07 -0700, Guido van Rossum wrote: > On Sun, Aug 16, 2020 at 5:45 AM Steven D'Aprano <[email protected]> > wrote: > > > On Mon, Aug 17, 2020 at 12:32:08AM +1200, Greg Ewing wrote: > > > On 16/08/20 11:49 am, Guido van Rossum wrote: > > > > SEMANTICS OF NO ARGUMENTS > > > > I can see two basic ways of allowing no arguments. One is > > > > for the > > > > interpreter to construct an object that is the argument > > > > passed to > > > > __getitem__ and so forth. The other is to not pass an > > > > argument at > > > > all. I see this as a secondary question. > > > > > > If d[] were to be allowed, I would expect it to pass an empty > > > tuple as the index, since it's the limiting case of reducing the > > > number of positional indices. > > > > So you would expect `obj[]` and `obj[()]` to be the same? > > > > That's not terrible, since these are also the same: > ``` > obj[x] === obj[(x)] > obj[x, y] === obj[(x, y)] > ``` > (Even though `obj[x]` is still an exception because it's the only > form that > isn't tuplified.) > > On the other hand, it's *also* the limiting case of reducing the > number of > keyword arguments, so whatever is passed here should also be passed > as the > positional part of the key when only keyword arguments are present, > and I'm > not sure what I think of using `()` for that. > > > > Personally, I think that unless there is an overwhelmingly good > > use-case > > for an empty subscript, we should continue to treat empty > > subscripts > > (no positional or keyword arguments) as a syntax error. > > > > That's where I am too right now. But I think there may be at least a > _decent_ use case: the `Tuple` type in type annotations. (And since > PEP 585 > also the `tuple` type.) > > We have `Tuple[int, int]` as a tuple of two integers. And we have > `Tuple[int]` as a tuple of one integer. And occasionally we need to > spell a > tuple of *no* values, since that's the type of `()`. But we currently > are > forced to write that as `Tuple[()]`. If we allowed `Tuple[]` that odd > edge > case would be removed. > > So I probably would be okay with allowing `obj[]` syntactically, as > long as > the dict type could be made to reject it. > > Alas, I thought I had a solution, but it doesn't work for > `__setitem__`: we > can easily state that `obj[]` calls `obj.__getitem__()` and whether > that's > accepted or not depends on whether `obj.__getitem__` has a default > value > for its `key` positional argument. But what to do for `obj[] = x`? We > can't > call `obj.__setitem__(x)` -- well, we could, but it would be super > ugly to > write such a `__getitem__` method properly -- similar to supporting > `range(n)`. > > So my intuition is failing me. It looks like `d[] = x` will need to > come up > with *some* key, and the only two values that sound at all reasonable > are > `()` (for the reason Greg mentioned) and `None` (because it's the > universal > "nothing here" value). But either way it's not reasonable for `dict` > to > reject those keys -- they are legitimate keys when passed explicitly. > Using > `()` is slightly better because it helps debugging: if you have a > dict with > an unexpected `None` key you should look for a key computation that > unexpectedly returned `None`, and we can now add that if you have a > dict > with an unexpected `()` key, you should look for an assignment of the > form > `d[] = x`.
For what its worth, NumPy uses `None` to indicate inserting a new
axis/dimensions (we have an `np.newaxis` alias as well):
arr = np.array(5)
arr.ndim == 0
arr[None].ndim == arr[None,].ndim == 1
So that would be problematic. There are two (subtly different [1])
acceptable choices for `ndarray[]`:
arr[] is arr[()]
or:
arr[] is arr[...]
In either case, though, I guess the arguments above against `None`
apply likely similarly for `Ellipsis`. And since there are two
different choices refusing to choose is fair for NumPy itself (for some
other array-objects the result of those two choices may be identical).
- Sebastian
[1] The difference is that `arr[()]` extracts a scalar, while
`arr[...]` returns the array (container) unchanged. This difference
only matters for zero dimensional arrays. There may be reasons to
prefer one over the other, but I can't think of any right now.
>
> But it would be better if `d[] = x` could be simply rejected --
> either at
> runtime (perhaps with a TypeError, like for calling a function with
> insufficient arguments), or syntactically. (That is, if you believe,
> like
> me, that `d[key, kwd=val]` should be rejected.) Hence, `Tuple[]`
> qualifies
> as a decent use case, but not as an overwhelmingly good one.
>
> I can think of another way to deal with this -- we could define a new
> sentinel object (e.g. `Nope` :-), `d[]` could be equivalent to
> `d[Nope]`,
> and the dict class could reject `Nope` as a key value. But that's
> quite
> ugly, and it's arbitrary, too.
>
>
>
> PS. All this reminds me of a complaint I heard 4-5 decades ago from
> an
> experienced programmer when I was just learning the ropes, and which
> somehow stuck in my mind ever since: "... and yet again, the empty
> [sequence] is treated rather shabbily." (It sounded better in Dutch
> --
> "stiefmoederlijk", meaning "stepmotherly".)
>
> _______________________________________________
> Python-ideas mailing list -- [email protected]
> To unsubscribe send an email to [email protected]
> https://mail.python.org/mailman3/lists/python-ideas.python.org/
> Message archived at
> https://mail.python.org/archives/list/[email protected]/message/3AXKZGJCRBQOZDMR3FBG5YBKRKWR3U7D/
> Code of Conduct: http://python.org/psf/codeofconduct/
signature.asc
Description: This is a digitally signed message part
_______________________________________________ Python-ideas mailing list -- [email protected] To unsubscribe send an email to [email protected] https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/[email protected]/message/AC3NNTLGAA53M5MADTKMKKVICFDFQEOP/ Code of Conduct: http://python.org/psf/codeofconduct/
