*Memo:
The new syntax of generics is name[*/**parameter, ...] which can be used from Python 3.12:
-
name(Required):- It's an identifier.
-
[*/**parameter, ...](Required):- A
*/**parameteris a (positional-only generic) type parameter. -
*/**parametermust be at least one so the empty type parameter[]cannot be used. -
*/**(Optional):- It cannot be both
*and**. -
parameteris TypeVar base:- It can be more than one.
-
*parameteris TypeVarTuple base:- It cannot be more than one according to the reason.
-
**parameteris ParamSpec base:- It can be more than one.
- The old syntax
TypeVar,TypeVarTupleandParamSpeccan still be used. - For
TypeVarbase, variance is automatically inferred. - For
TypeVarTupleandParamSpecbase, variance is always invariant according to the doc but they can be covariant and contravariant, and contravariant according to the issue and the issue respectively.
- It cannot be both
-
parameterisname:bound/constraints=default:-
name(Required):- It's an identifier.
-
:bound/constraints(Optional):- It cannot be both
boundandconstraints. - It isn't supported for
TypeVarTupleandParamSpecbase by Python interpreter and type checkers. -
bound(Type:Type):- For
TypeVarbase:- It's a type.
- The type, its subtype and subtype-like type can be accepted as type arguments.
- For
-
constraints(Type:tuple(Type)):- For
TypeVar:- It must be at least two types.
- The types can be but their subtypes and subtype-like types cannot be accepted as type arguments.
- For
- It cannot be both
-
=default(Optional):-
default(Type:Type):- For
TypeVar:- It's a default type.
- If
constraintsis set, it must be one type ofconstraintsbut not their subtype or subtype-like type. - If
boundis set, it must be the type, subtype or subtype-like type ofbound.
- For
TypeVarTuplebase:- It's a default unpacked tuple.
- It doesn't work according to the issue.
- For
ParamSpec:- It's a list of default types.
- If
boundis set, it must be the types, subtypes and subtype-like types ofboundin a list.
- For
-
-
- A
The old syntax of generics is TypeVar, TypeVarTuple and ParamSpec:
- For
TypeVar:- The 1st parameter is
name(Required-KP-Type:str):- It's an identifier.
- It must be the same name as its variable.
- In convention,
T.*is used likeT,T1,T2, etc.
- The 2nd parameter is
*constraints(Optional-VP-Default:()-Type:Type):- It's two or more types.
- The types can be but their subtypes and subtype-like types cannot be accepted as type arguments.
- The 3rd parameter is
bound(Optional-KO-Default:None-Type:Type):- It's a type.
- The type, its subtype and subtype-like type can be accepted as type arguments.
- The 4th parameter is
covariant(Optional-KO-Default:False-Type:bool). - The 5th parameter is
contravariant(Optional-KO-Default:False-Type:bool). - The 6th parameter is
infer_variance(Optional-KO-Default:False-Type:bool). - The 7th parameter is
default(Optional-KO-Default:NoDefault-Type:Type):- It's a default type.
- If
*constraintsis set, it must be one type of*constraintsbut not their subtype or subtype-like type. - If
boundis set, it must be the type, subtype or subtype-like type ofbound.
- Only one of
*constraintsorboundcan be set but not two. - By default, variance is invariant.
- Only one of
covariant,contravariantorinfer_variancecan be set but not more than one. - mypy doesn't support
infer_varianceaccording to the issue.
- The 1st parameter is
- For
TypeVarTuple:- The 1st parameter is
name(Required-KP-Type:str):- It's an identifier.
- It must be the same name as its variable.
- In convention,
Ts.*is used likeTs,Ts1,Ts2, etc.
- The 2nd parameter is
default(Optional-KO-Default:NoDefault-Type:Type): - Variance is always invariant according to the doc but it can be covariant and contravariant according to the issue.
- The 1st parameter is
- For
ParamSpec:- The 1st parameter is
name(Required-KP-Type:str):- It's an identifier.
- It must be the same name as its variable.
- In convention,
P.*is used likeP,P1,P2, etc.
- The 2nd parameter is
bound(Optional-KO-Default:None-Type:Type) (Not supported):- It's a list of types.
- The types in a list, their subtypes and subtype-like types can be accepted as type arguments.
- The 3rd parameter is
covariant(Optional-KO-Default:False-Type:bool) (Not supported). - The 4th parameter is
contravariant(Optional-KO-Default:False-Type:bool) (Not supported). - The 5th parameter is
default(Optional-KO-Default:NoDefault-Type:Type):- It's a list of default types.
- If
boundis set, it must be the types, subtypes and subtype-like types ofboundin a list.
- Type checkers don't support
bound,covariantandcontravariant. - Variance is always invariant according to the doc but it can be contravariant according to the issue.
- With mypy, using
namekeyword argument gets error, which is a bug according to the issue.
- The 1st parameter is
The generic type syntax of generics is type[argument, ...] for both the new and old syntax of generics:
-
type(Required-Type:Type):- It's a type.
-
[argument, ...](Optional):- An
argumentis a (positional-only generic) type argument. -
argumentmust be at least one so the empty type argument[]cannot be used. - It can be omitted as long as:
- all the type parameters have default types whether mypy is run with or without
--strict. - or mypy is run without
--strictwhether all the type parameters have default types or not:- Any is set to the type parameters without default types.
- all the type parameters have default types whether mypy is run with or without
-
argument(Required-Type:Type):- For
TypeVarbase, it's a type. - For
TypeVarTuplebase, it's a type or an unpacked tuple of one or more types. - For
ParamSpecbase, it's a type or a list of zero or more types. - For it, a tuple can be used according to the issue.
- For
- An
variance:
- is the feature of generics to decide whether a type accepts its supertypes, supertype-like types, subtypes and subtype-like types in addition to the type:
- has 3 kinds invariance, covariance and contravariance:
- Invariance only makes a type accept the type.
- Covariance makes a type accept the type, its subtypes and subtype-like types.
- Contravariance make a type accept the type, its supertypes and supertype-like types.
- is inferred for only
TypeVar(base) in the new and old syntax of generics:- In the old syntax, variance inference happens if
infer_variance=Trueis set toTypeVar:- mypy doesn't support
infer_varianceaccording to the issue.
- mypy doesn't support
-
TypeVarTupleandParamSpec(base) are alwaysinvariantaccording to the doc but they can be covariant and contravariant, and contravariant according to the issue and the issue respectively.
- In the old syntax, variance inference happens if
- This is how variance is inferred:
- Covariant if the variable in a class can be read but cannot be written from outside the class.
- Contravariant if the variable in a class can be written but cannot be read from outside the class.
- Invariant if the variable in a class can be read and written from outside the class.
| Inferred Variance | Reason | Example |
|---|---|---|
| Covariant | Read-Only | Callable[[], T] & tuple |
| Contravariant | Write-Only | Callable[[T], None] |
| Invariant | Read-Write | Callable[[T], T] & list |
Top comments (0)