ASCIIfy PEP 483
This commit is contained in:
parent
9ba23eff34
commit
24dc240fc2
56
pep-0483.txt
56
pep-0483.txt
|
@ -40,8 +40,8 @@ Summary of gradual typing
|
||||||
We define a new relationship, is-consistent-with, which is similar to
|
We define a new relationship, is-consistent-with, which is similar to
|
||||||
is-subclass-of, except it is not transitive when the new type **Any** is
|
is-subclass-of, except it is not transitive when the new type **Any** is
|
||||||
involved. (Neither relationship is symmetric.) Assigning x to y is OK if
|
involved. (Neither relationship is symmetric.) Assigning x to y is OK if
|
||||||
the type of x is consistent with the type of y. (Compare this to “... if
|
the type of x is consistent with the type of y. (Compare this to "... if
|
||||||
the type of x is a subclass of the type of y,” which states one of the
|
the type of x is a subclass of the type of y," which states one of the
|
||||||
fundamentals of OO programming.) The is-consistent-with relationship is
|
fundamentals of OO programming.) The is-consistent-with relationship is
|
||||||
defined by three rules:
|
defined by three rules:
|
||||||
|
|
||||||
|
@ -58,12 +58,12 @@ for a longer explanation and motivation. Note that rule 3 places **Any**
|
||||||
at the root of the class graph. This makes it very similar to
|
at the root of the class graph. This makes it very similar to
|
||||||
**object**. The difference is that **object** is not consistent with
|
**object**. The difference is that **object** is not consistent with
|
||||||
most types (e.g. you can't use an object() instance where an int is
|
most types (e.g. you can't use an object() instance where an int is
|
||||||
expected). IOW both **Any** and **object** mean “any type is allowed”
|
expected). IOW both **Any** and **object** mean "any type is allowed"
|
||||||
when used to annotate an argument, but only **Any** can be passed no
|
when used to annotate an argument, but only **Any** can be passed no
|
||||||
matter what type is expected (in essence, **Any** shuts up complaints
|
matter what type is expected (in essence, **Any** shuts up complaints
|
||||||
from the static checker).
|
from the static checker).
|
||||||
|
|
||||||
Here's an example showing how these rules work out in practice:
|
Here's an example showing how these rules work out in practice:
|
||||||
|
|
||||||
Say we have an Employee class, and a subclass Manager:
|
Say we have an Employee class, and a subclass Manager:
|
||||||
|
|
||||||
|
@ -72,7 +72,7 @@ Say we have an Employee class, and a subclass Manager:
|
||||||
|
|
||||||
Let's say variable e is declared with type Employee:
|
Let's say variable e is declared with type Employee:
|
||||||
|
|
||||||
- e = Employee() # type: Employee
|
- e = Employee() # type: Employee
|
||||||
|
|
||||||
Now it's okay to assign a Manager instance to e (rule 1):
|
Now it's okay to assign a Manager instance to e (rule 1):
|
||||||
|
|
||||||
|
@ -81,40 +81,40 @@ Now it's okay to assign a Manager instance to e (rule 1):
|
||||||
It's not okay to assign an Employee instance to a variable declared with
|
It's not okay to assign an Employee instance to a variable declared with
|
||||||
type Manager:
|
type Manager:
|
||||||
|
|
||||||
- m = Manager() # type: Manager
|
- m = Manager() # type: Manager
|
||||||
- m = Employee() # Fails static check
|
- m = Employee() # Fails static check
|
||||||
|
|
||||||
However, suppose we have a variable whose type is **Any**:
|
However, suppose we have a variable whose type is **Any**:
|
||||||
|
|
||||||
- a = some\_func() # type: Any
|
- a = some\_func() # type: Any
|
||||||
|
|
||||||
Now it's okay to assign a to e (rule 2):
|
Now it's okay to assign a to e (rule 2):
|
||||||
|
|
||||||
- e = a # OK
|
- e = a # OK
|
||||||
|
|
||||||
Of course it's also okay to assign e to a (rule 3), but we didn't need
|
Of course it's also okay to assign e to a (rule 3), but we didn't need
|
||||||
the concept of consistency for that:
|
the concept of consistency for that:
|
||||||
|
|
||||||
- a = e # OK
|
- a = e # OK
|
||||||
|
|
||||||
|
|
||||||
Notational conventions
|
Notational conventions
|
||||||
----------------------
|
----------------------
|
||||||
|
|
||||||
- t1, t2 etc. and u1, u2 etc. are types or classes. Sometimes we write
|
- t1, t2 etc. and u1, u2 etc. are types or classes. Sometimes we write
|
||||||
ti or tj to refer to “any of t1, t2, etc.”
|
ti or tj to refer to "any of t1, t2, etc."
|
||||||
- X, Y etc. are type variables (defined with Var(), see below).
|
- X, Y etc. are type variables (defined with Var(), see below).
|
||||||
- C, D etc. are classes defined with a class statement.
|
- C, D etc. are classes defined with a class statement.
|
||||||
- x, y etc. are objects or instances.
|
- x, y etc. are objects or instances.
|
||||||
- We use the terms type and class interchangeably, and we assume
|
- We use the terms type and class interchangeably, and we assume
|
||||||
type(x) is x.\_\_class\_\_.
|
type(x) is x.\_\_class\_\_.
|
||||||
|
|
||||||
|
|
||||||
General rules
|
General rules
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
- Instance-ness is derived from class-ness, e.g. x is an instance of
|
- Instance-ness is derived from class-ness, e.g. x is an instance of
|
||||||
t1 if type(x) is a subclass of t1.
|
t1 if type(x) is a subclass of t1.
|
||||||
- No types defined below (i.e. Any, Union etc.) can be instantiated.
|
- No types defined below (i.e. Any, Union etc.) can be instantiated.
|
||||||
(But non-abstract subclasses of Generic can be.)
|
(But non-abstract subclasses of Generic can be.)
|
||||||
- No types defined below can be subclassed, except for Generic and
|
- No types defined below can be subclassed, except for Generic and
|
||||||
|
@ -136,7 +136,7 @@ Types
|
||||||
Union the result is flattened. (Example: Union[int, Union[float,
|
Union the result is flattened. (Example: Union[int, Union[float,
|
||||||
str]] == Union[int, float, str].) If ti and tj have a subclass
|
str]] == Union[int, float, str].) If ti and tj have a subclass
|
||||||
relationship, the less specific type survives. (Example:
|
relationship, the less specific type survives. (Example:
|
||||||
Union[Employee, Manager] == Union[Employee].) Union[t1] returns just
|
Union[Employee, Manager] == Union[Employee].) Union[t1] returns just
|
||||||
t1. Union[] is illegal, so is Union[()]. Corollary: Union[..., Any,
|
t1. Union[] is illegal, so is Union[()]. Corollary: Union[..., Any,
|
||||||
...] returns Any; Union[..., object, ...] returns object; to cut a
|
...] returns Any; Union[..., object, ...] returns object; to cut a
|
||||||
tie, Union[Any, object] == Union[object, Any] == Any.
|
tie, Union[Any, object] == Union[object, Any] == Any.
|
||||||
|
@ -154,13 +154,13 @@ Types
|
||||||
argument types t1 etc., and return type tr. The argument list may be
|
argument types t1 etc., and return type tr. The argument list may be
|
||||||
empty (n==0). There is no way to indicate optional or keyword
|
empty (n==0). There is no way to indicate optional or keyword
|
||||||
arguments, nor varargs (we don't need to spell those often enough to
|
arguments, nor varargs (we don't need to spell those often enough to
|
||||||
complicate the syntax — however, Reticulated Python has a useful idea
|
complicate the syntax - however, Reticulated Python has a useful idea
|
||||||
here). This is covariant in the return type, but contravariant in the
|
here). This is covariant in the return type, but contravariant in the
|
||||||
arguments. “Covariant” here means that for two callable types that
|
arguments. "Covariant" here means that for two callable types that
|
||||||
differ only in the return type, the subclass relationship for the
|
differ only in the return type, the subclass relationship for the
|
||||||
callable types follows that of the return types. (Example:
|
callable types follows that of the return types. (Example:
|
||||||
Callable[[], Manager] is a subclass of Callable[[], Employee].)
|
Callable[[], Manager] is a subclass of Callable[[], Employee].)
|
||||||
“Contravariant” here means that for two callable types that differ
|
"Contravariant" here means that for two callable types that differ
|
||||||
only in the type of one argument, the subclass relationship for the
|
only in the type of one argument, the subclass relationship for the
|
||||||
callable types goes in the opposite direction as for the argument
|
callable types goes in the opposite direction as for the argument
|
||||||
types. (Example: Callable[[Employee], None] is a subclass of
|
types. (Example: Callable[[Employee], None] is a subclass of
|
||||||
|
@ -198,13 +198,13 @@ are still controversial or not fully specified.)
|
||||||
- Type aliases, e.g.
|
- Type aliases, e.g.
|
||||||
|
|
||||||
* point = Tuple[float, float]
|
* point = Tuple[float, float]
|
||||||
* def distance(p: point) -> float: ...
|
* def distance(p: point) -> float: ...
|
||||||
|
|
||||||
- Forward references via strings, e.g.
|
- Forward references via strings, e.g.
|
||||||
|
|
||||||
* class C:
|
* class C:
|
||||||
|
|
||||||
+ def compare(self, other: “C”) -> int: ...
|
+ def compare(self, other: "C") -> int: ...
|
||||||
|
|
||||||
- If a default of None is specified, the type is implicitly optional, e.g.
|
- If a default of None is specified, the type is implicitly optional, e.g.
|
||||||
|
|
||||||
|
@ -213,11 +213,11 @@ are still controversial or not fully specified.)
|
||||||
- Don't use dynamic type expressions; use builtins and imported types
|
- Don't use dynamic type expressions; use builtins and imported types
|
||||||
only. No 'if'.
|
only. No 'if'.
|
||||||
|
|
||||||
* def display(message: str if WINDOWS else bytes): # NOT OK
|
* def display(message: str if WINDOWS else bytes): # NOT OK
|
||||||
|
|
||||||
- Type declaration in comments, e.g.
|
- Type declaration in comments, e.g.
|
||||||
|
|
||||||
* x = [] # type: Sequence[int]
|
* x = [] # type: Sequence[int]
|
||||||
|
|
||||||
- Type declarations using Undefined, e.g.
|
- Type declarations using Undefined, e.g.
|
||||||
|
|
||||||
|
@ -237,7 +237,7 @@ generics <http://mypy.readthedocs.org/en/latest/generics.html>`_.)
|
||||||
the variable name.
|
the variable name.
|
||||||
|
|
||||||
- **Y = Var('Y', t1, t2, ...).** Ditto, constrained to t1 etc. Behaves
|
- **Y = Var('Y', t1, t2, ...).** Ditto, constrained to t1 etc. Behaves
|
||||||
like Union[t1, t2, ...] for most purposes, but when used as a type
|
like Union[t1, t2, ...] for most purposes, but when used as a type
|
||||||
variable, subclasses of t1 etc. are replaced by the most-derived base
|
variable, subclasses of t1 etc. are replaced by the most-derived base
|
||||||
class among t1 etc.
|
class among t1 etc.
|
||||||
|
|
||||||
|
@ -249,9 +249,9 @@ generics <http://mypy.readthedocs.org/en/latest/generics.html>`_.)
|
||||||
|
|
||||||
- return a if len(a) >= len(b) else b
|
- return a if len(a) >= len(b) else b
|
||||||
|
|
||||||
* x = longest('a', 'abc') # The inferred type for x is str
|
* x = longest('a', 'abc') # The inferred type for x is str
|
||||||
|
|
||||||
* y = longest('a', b'abc') # Fails static type check
|
* y = longest('a', b'abc') # Fails static type check
|
||||||
|
|
||||||
* In this example, both arguments to longest() must have the same type
|
* In this example, both arguments to longest() must have the same type
|
||||||
(str or bytes), and moreover, even if the arguments are instances of a
|
(str or bytes), and moreover, even if the arguments are instances of a
|
||||||
|
@ -290,7 +290,7 @@ generics <http://mypy.readthedocs.org/en/latest/generics.html>`_.)
|
||||||
|
|
||||||
- **class C(Generic[X, Y, ...]):** ... Define a generic class C over type
|
- **class C(Generic[X, Y, ...]):** ... Define a generic class C over type
|
||||||
variables X etc. C itself becomes parameterizable, e.g. C[int, str, ...]
|
variables X etc. C itself becomes parameterizable, e.g. C[int, str, ...]
|
||||||
is a specific class with substitutions X→int etc.
|
is a specific class with substitutions X->int etc.
|
||||||
|
|
||||||
- TODO: Explain use of generic types in function signatures. E.g.
|
- TODO: Explain use of generic types in function signatures. E.g.
|
||||||
Sequence[X], Sequence[int], Sequence[Tuple[X, Y, Z]], and mixtures.
|
Sequence[X], Sequence[int], Sequence[Tuple[X, Y, Z]], and mixtures.
|
||||||
|
@ -316,7 +316,7 @@ module <https://github.com/JukkaL/typing/blob/master/typing.py>`_.)
|
||||||
Another reference
|
Another reference
|
||||||
-----------------
|
-----------------
|
||||||
|
|
||||||
Lest mypy gets all the attention, I should mention \ `Reticulated
|
Lest mypy gets all the attention, I should mention \ `Reticulated
|
||||||
Python <https://github.com/mvitousek/reticulated>`_ by Michael Vitousek
|
Python <https://github.com/mvitousek/reticulated>`_ by Michael Vitousek
|
||||||
as an example of a slightly different approach to gradual typing for
|
as an example of a slightly different approach to gradual typing for
|
||||||
Python. It is described in an actual `academic
|
Python. It is described in an actual `academic
|
||||||
|
|
Loading…
Reference in New Issue