
This was previously discussed in https://github.com/python/typing/issues/307.
It would often be useful to be able to specify a default type for type vars. A few examples:
* Counter is most likely used with ints in the vast majority of cases. Being able to write "Counter" instead of "Counter[int]" makes sense to me. * Currently, when marking a previously non-generic type as generic, it will break existing type annotations. Having a default value works around this. To use Counter as an example again: Currently it is non-generic, but making it generic would break existing annotations. Adding a default of "int" would work around this problem. * Another example from the issue above: Using a default of None can prevent overloads, as in the following example: "def nullcontext(enter_result: _T = ...) -> ContextManager[_T]: ...". Without the default we need an explicit overload for the case where no argument is provided, because otherwise the type checker can't know the type of _T. While this is not a big problem in stubs, I find overloads quite obnoxious in implementations.
While of course not completely comparable, I find myself using generic defaults quite often when working with TypeScript. A few examples as anectodal evidence:
* We have functions that fetch JSON from an API. They are generic over the return type and default to a general JSON type, but can be overwritten if the response shape is known. (Because we control the API.) * We have a few cases, where an object is generic over a list of strings. Take a class wrapping HTML <select> elements. Sometimes all the possible options are known to the application, and have semantic meaning. (For example for choosing a view.) So it makes sense to declare a class like "class Select[Literal["foo", "bar"]]" (using Python syntax). It's then possible to have "Select.value" have the type "Literal["foo", "bar"]". In other cases, the possible options are unknown (taken from a database, for example). In that case, using "class Select[str]" would make sense. The latter is also a sensible default. * Generally I tend to use more type variables per type in TypeScript than in Python, partially due to the fact that some of them can be set to sensible defaults. While it would be obnoxious to always define four generics everytime you use a type, in typeshed I only have to define one of them with the others having sensible defaults.
What do other people think about this and how would we proceed if this is deemed useful?
- Sebastian

It would be super useful for us (dry-python). That's what I can say for sure.
Our use-case:
We define lots of interfaces like `MappableN` or `FunctorN`, it can potentially work with: - 1 type argument, like `Maybe[int]` or `List[int]` - 2 type arguments, like `Result[int, str]` or `Dict[str, int]` - 3 type arguments, like `ReaderIOResult[int, str, env]` or `Generator[x, y, z]`
We now have to use a lot of aliases with different numbers of expected arguments. We turn `MappableN` into `Mappable1`, `Mappable2`, `Mappable3`.
Source: https://github.com/dry-python/returns/blob/master/returns/interfaces/mappabl...
Default type args would make this 3 times easier :)
пт, 4 сент. 2020 г. в 12:32, Sebastian Rittau srittau@rittau.biz:
This was previously discussed in https://github.com/python/typing/issues/307.
It would often be useful to be able to specify a default type for type vars. A few examples:
- Counter is most likely used with ints in the vast majority of cases. Being able to write "Counter" instead of "Counter[int]" makes sense to me.
- Currently, when marking a previously non-generic type as generic, it will break existing type annotations. Having a default value works around this. To use Counter as an example again: Currently it is non-generic, but making it generic would break existing annotations. Adding a default of "int" would work around this problem.
- Another example from the issue above: Using a default of None can prevent overloads, as in the following example: "def nullcontext(enter_result: _T = ...) -> ContextManager[_T]: ...". Without the default we need an explicit overload for the case where no argument is provided, because otherwise the type checker can't know the type of _T. While this is not a big problem in stubs, I find overloads quite obnoxious in implementations.
While of course not completely comparable, I find myself using generic defaults quite often when working with TypeScript. A few examples as anectodal evidence:
- We have functions that fetch JSON from an API. They are generic over the return type and default to a general JSON type, but can be overwritten if the response shape is known. (Because we control the API.)
- We have a few cases, where an object is generic over a list of strings. Take a class wrapping HTML <select> elements. Sometimes all the possible options are known to the application, and have semantic meaning. (For example for choosing a view.) So it makes sense to declare a class like "class Select[Literal["foo", "bar"]]" (using Python syntax). It's then possible to have "Select.value" have the type "Literal["foo", "bar"]". In other cases, the possible options are unknown (taken from a database, for example). In that case, using "class Select[str]" would make sense. The latter is also a sensible default.
- Generally I tend to use more type variables per type in TypeScript than in Python, partially due to the fact that some of them can be set to sensible defaults. While it would be obnoxious to always define four generics everytime you use a type, in typeshed I only have to define one of them with the others having sensible defaults.
What do other people think about this and how would we proceed if this is deemed useful?
- Sebastian
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: n.a.sobolev@gmail.com

On Fri, Sep 4, 2020, at 12:31, Sebastian Rittau wrote:
This was previously discussed in https://github.com/python/typing/issues/307.
It would often be useful to be able to specify a default type for type vars. A few examples:
I, too, have wanted this multiple times, and agree with all the reasons laid out by Sebastian.
One common case I can add is `Generator[Foo, None, None]`. I think it would make a lot of sense to default `SendType` and `ReturnType` to None.
There is a workaround mentioned in the issue of using a type alias, e.g.
SimpleGenerator = Generator[T, None, None]
but this requires coming up with a name and complicating the API, which never pulls its weight.
So I wonder if anyone has a good idea for a syntax?
One suggestion is
T = TypeVar("T", default=int)
but I personally don't like it for two reasons:
1. I think the default is more of a property of the generic type than the TypeVar itself, which can be reused in multiple types.
2. I think it causes an ambiguity when a default is followed by non-defaults, e.g. given
YieldType = TypeVar("YieldType") SendType = TypeVar("SendType, default=int) ReturnType = TypeVar("ReturnType") class Generator(Generic[YieldType, SendType, ReturnType]): ...
how should `Generator[str, bytes]` be interpreted?
Of course it would have been ideal if it were possible to use the exact same syntax and semantics (minus the types) of function arguments, even including positional-only and keyword-only type parameters, but I don't see how it works out syntactically. Maybe one of the newer PEPs help here?
Ran
participants (3)
-
Ran Benita
-
Sebastian Rittau
-
Никита Соболев