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
|
||||
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
|
||||
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 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
|
||||
fundamentals of OO programming.) The is-consistent-with relationship is
|
||||
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
|
||||
**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
|
||||
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
|
||||
matter what type is expected (in essence, **Any** shuts up complaints
|
||||
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:
|
||||
|
||||
|
@ -72,7 +72,7 @@ Say we have an Employee class, and a subclass Manager:
|
|||
|
||||
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):
|
||||
|
||||
|
@ -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
|
||||
type Manager:
|
||||
|
||||
- m = Manager() # type: Manager
|
||||
- m = Employee() # Fails static check
|
||||
- m = Manager() # type: Manager
|
||||
- m = Employee() # Fails static check
|
||||
|
||||
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):
|
||||
|
||||
- e = a # OK
|
||||
- e = a # OK
|
||||
|
||||
Of course it's also okay to assign e to a (rule 3), but we didn't need
|
||||
the concept of consistency for that:
|
||||
|
||||
- a = e # OK
|
||||
- a = e # OK
|
||||
|
||||
|
||||
Notational conventions
|
||||
----------------------
|
||||
|
||||
- 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.”
|
||||
- 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."
|
||||
- X, Y etc. are type variables (defined with Var(), see below).
|
||||
- C, D etc. are classes defined with a class statement.
|
||||
- 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\_\_.
|
||||
|
||||
|
||||
General rules
|
||||
-------------
|
||||
|
||||
- Instance-ness is derived from class-ness, e.g. x is an instance of
|
||||
t1 if type(x) is a subclass of t1.
|
||||
- Instance-ness is derived from class-ness, e.g. x is an instance of
|
||||
t1 if type(x) is a subclass of t1.
|
||||
- No types defined below (i.e. Any, Union etc.) can be instantiated.
|
||||
(But non-abstract subclasses of Generic can be.)
|
||||
- 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,
|
||||
str]] == Union[int, float, str].) If ti and tj have a subclass
|
||||
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,
|
||||
...] returns Any; Union[..., object, ...] returns object; to cut a
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
callable types follows that of the return types. (Example:
|
||||
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
|
||||
callable types goes in the opposite direction as for the argument
|
||||
types. (Example: Callable[[Employee], None] is a subclass of
|
||||
|
@ -198,13 +198,13 @@ are still controversial or not fully specified.)
|
|||
- Type aliases, e.g.
|
||||
|
||||
* point = Tuple[float, float]
|
||||
* def distance(p: point) -> float: ...
|
||||
* def distance(p: point) -> float: ...
|
||||
|
||||
- Forward references via strings, e.g.
|
||||
|
||||
* 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.
|
||||
|
||||
|
@ -213,11 +213,11 @@ are still controversial or not fully specified.)
|
|||
- Don't use dynamic type expressions; use builtins and imported types
|
||||
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.
|
||||
|
||||
* x = [] # type: Sequence[int]
|
||||
* x = [] # type: Sequence[int]
|
||||
|
||||
- Type declarations using Undefined, e.g.
|
||||
|
||||
|
@ -237,7 +237,7 @@ generics <http://mypy.readthedocs.org/en/latest/generics.html>`_.)
|
|||
the variable name.
|
||||
|
||||
- **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
|
||||
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
|
||||
|
||||
* 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
|
||||
(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
|
||||
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.
|
||||
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
|
||||
-----------------
|
||||
|
||||
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
|
||||
as an example of a slightly different approach to gradual typing for
|
||||
Python. It is described in an actual `academic
|
||||
|
|
Loading…
Reference in New Issue