After the discussion on type var defaults, Guido and I had a short
discussion about a potential inline-definition syntax for type vars.
Such a syntax has a few advantages over the definition using TypeVar:
* The type vars would be defined close to where they are actually used.
* Type vars would not leak their name into the module-global scope.
* Removes the duplication from TypeVar: _T = TypeVar("_T")
* This is in line with what other languages are doing and so more
familiar for developers coming from other languages.
Even if we implement an inline syntax, TypeVar should not be deprecated
as it's still quite useful for defining re-usable type vars like
Here are a few proposals we came up with.
Inline syntax using square brackets
class C[T, S]:
def foo[R=int](self) -> R: pass
Some ideas how we could express upper bounds, constraints, and variance:
* Upper bounds: [R(Base1 | Base2)] or [R from Base1 | Base2].
* Constraints: [R as Base1 | Base2]
* Variance: [R(covariant=True)]
* Similar syntax to existing generics syntax.
* Used by languages such as Go and Scala.
* Square brackets are already used for indexes/slices and generics.
* We have a bit of a "bracket hell", which does not help readability:
def foo[F=dict[str, Callable[[int], object]]](): pass
Inline syntax using angle brackets
class C<T, S>:
def foo<R>(self) -> R: pass
* Angle brackets are currently unused in Python and lower than/greater
than is not used within type context.
* Using angle brackets could reduce "bracket hell".
* Used by languages like C++, Java, C#, TypeScript, Delphi, so should be
fairly similar to developers coming from popular languages.
* Slightly inconsistent with existing generic syntax.
def foo(self) -> R: pass
* Doesn't require syntax changes to Python.
* Very readable (in my opinion), because it has one type var per line,
especially with more complex type vars.
* Is defined exactly like a TypeVar(), but without assigning it to a name.
* Flexible and extensible as it's using regular decorator syntax.
* Backwards compatible as it could be added to typing_extensions.
* More verbose than the other suggestions, especially when using simple
* Non-standard syntax, compared to other languages.
* Currently requires either quoted types or "from __future__ import
My personal favorite is the decorator syntax, for all the advantages
listed. The disadvantages seem minor to me or temporary. Being more
verbose makes is actually more readable. When writing TypeScript, I
often have monsters like this:
A extends Action = AnyAction,
E = undefined,
I believe that the Python equivalent using decorator would be more readable:
@typevar("A", bound=Action, default=AnyAction)