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, which is "argument x must be specified with a value of type T, or it must be omitted (and the default value used)". In other words, a usage like f(x=MISSING) would be rejected by the type checker (assuming that MISSING was not a value of type T), but f() would be valid. The code inside f would be checked on the basis that x is either type T or it's the default value. If `Optional` wasn't already taken to mean "or None", I'd write this as `def f(x=MISSING: Optional[T])`
Yes, there are edge cases where people might need to explicitly pass the sentinel, but they are rare enough that having to annotate that with a "don't check the types, I know what I'm doing" directive is reasonable in that case.
I don't think it's possible to express that with type annotations at the moment, but maybe it's worth considering? Paul _______________________________________________ Typing-sig mailing list -- typing-sig@python.org To unsubscribe send an email to typing-sig-leave@python.org https://mail.python.org/mailman3/lists/typing-sig.python.org/ Member address: alex.waygood@gmail.com