ASCIIfy PEP 483

This commit is contained in:
Chris Angelico 2015-01-10 05:28:21 +11:00
parent 9ba23eff34
commit 24dc240fc2
1 changed files with 28 additions and 28 deletions

View File

@ -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 Xint 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