Paul Moore writes:
Maybe what needs to be expressed here is the actual intention, which
is "argument x must be specified with a value of type T, or it must be
omitted (and the default value used)".
I believe this can be expressed using overloads:
```
from typing import overload
from sentinel import Sentinel
MISSING = Sentinel("MISSING")
@overload
def f() -> int: ...
@overload
def f(arg: str) -> str: ...
def f(arg: str | Sentinel = MISSING) -> int | str:
if arg is MISSING:
return 42
return arg
```
MyPy is actually pretty happy about this (try it out on Mypy playground here: https://mypy-play.net/?mypy=latest&python=3.10&flags=show-error-codes%2Cstrict&gist=975fc21b03d3131eca08529d0e0e506d) — the only bit it doesn't understand is that `if arg is MISSING` acts as a type-narrowing clause, so you have to alter the last line of the runtime implementation to `return typing.cast(str, arg)`.
However:
- That's pretty complicated if we're saying you need to do that every time you want to use a sentinel.
- I don't like that this leaves open the "edge case" for when people do need to explicitly pass in the sentinel value. With ^this way of typing the function, MyPy will raise an error if anybody does explicitly pass in the sentinel value. That's very desirable for something like dataclasses.MISSING, where users of the library really shouldn't ever be using it directly. But, there will surely be some cases where it's not desirable, and that will cause bug reports.
Best,
Alex
On 19 Oct 2021, at 10:21, Paul Moore <p.f.moore@gmail.com> wrote:
On Tue, 19 Oct 2021 at 09:50, Sebastian Rittau <srittau@rittau.biz> wrote:
Am 17.10.21 um 11:24 schrieb Tal Einat:
Hi typing folks,
I'm continuing to pursue adding a tool for defining sentinel values to
the standard library. See PEP 616 [1], previous discussion [2] and
previous thread on this mailing list [3], for more background and details.
The gist of the proposal is to add a function or class, e.g.
Sentinel(), for defining sentinels in a standard way, providing nice
properties such as clear reprs, support for strict type signatures and
surviving copying/unpickling.
Without going into implementation details, I would also like to echo
that I don't like the Literal syntax. This seems like unnecessary visual
noise. Literal was necessary for strings due to the ambiguous nature of
quoted annotation and was extended to other literals for consistency. I
don't think either of these arguments are applicable for sentinel values.
Maybe what needs to be expressed here is the actual intention, whichis "argument x must be specified with a value of type T, or it must beomitted (and the default value used)". In other words, a usage likef(x=MISSING) would be rejected by the type checker (assuming thatMISSING was not a value of type T), but f() would be valid. The codeinside f would be checked on the basis that x is either type T or it'sthe default value. If `Optional` wasn't already taken to mean "orNone", I'd write this as `def f(x=MISSING: Optional[T])`Yes, there are edge cases where people might need to explicitly passthe sentinel, but they are rare enough that having to annotate thatwith a "don't check the types, I know what I'm doing" directive isreasonable in that case.I don't think it's possible to express that with type annotations atthe moment, but maybe it's worth considering?Paul_______________________________________________Typing-sig mailing list -- typing-sig@python.orgTo unsubscribe send an email to typing-sig-leave@python.orghttps://mail.python.org/mailman3/lists/typing-sig.python.org/Member address: alex.waygood@gmail.com