Add scoping rules for type variables to PEP 484 (#63)
Also clarify the description of NewType() a bit. Fixes python/typing#249
This commit is contained in:
parent
f312480a3b
commit
78478bc886
96
pep-0484.txt
96
pep-0484.txt
|
@ -448,6 +448,92 @@ is not generic but implicitly inherits from ``Iterable[Any]``::
|
||||||
Generic metaclasses are not supported.
|
Generic metaclasses are not supported.
|
||||||
|
|
||||||
|
|
||||||
|
Scoping rules for type variables
|
||||||
|
--------------------------------
|
||||||
|
|
||||||
|
Type variables follow normal name resolution rules.
|
||||||
|
However, there are some special cases in the static typechecking context:
|
||||||
|
|
||||||
|
* A type variable used in a generic function could be inferred to be equal to
|
||||||
|
different types in the same code block. Example::
|
||||||
|
|
||||||
|
from typing import TypeVar, Generic
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
|
||||||
|
def fun_1(x: T) -> T: ... # T here
|
||||||
|
def fun_2(x: T) -> T: ... # and here could be different
|
||||||
|
|
||||||
|
fun_1(1) # This is OK, T is inferred to be int
|
||||||
|
fun_2('a') # This is aslo OK, now T is str
|
||||||
|
|
||||||
|
* A type variable used in a method of a generic class that coincisides
|
||||||
|
with one of the variables that parameterize this class is always bound
|
||||||
|
to that variable. Example::
|
||||||
|
|
||||||
|
from typing import TypeVar, Generic
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
|
||||||
|
class MyClass(Generic[T]):
|
||||||
|
def meth_1(self, x: T) -> T: ... # T here
|
||||||
|
def meth_2(self, x: T) -> T: ... # and here are always the same
|
||||||
|
|
||||||
|
a = MyClass() # type: MyClass[int]
|
||||||
|
a.meth_1(1) # OK
|
||||||
|
a.meth_2('a') # This is an error!
|
||||||
|
|
||||||
|
* A type variable used in a method that does not match any of the variables
|
||||||
|
that parameterize the class makes this method a generic function in that
|
||||||
|
variable::
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
S = TypeVar('S')
|
||||||
|
class Foo(Generic[T]):
|
||||||
|
def method(self, x: T, y: S) -> S:
|
||||||
|
...
|
||||||
|
|
||||||
|
x = Foo() # type: Foo[int]
|
||||||
|
y = x.method(0, "abc") # inferred type of y is str
|
||||||
|
|
||||||
|
* Unbound type variables should not appear in the bodies of generic functions,
|
||||||
|
or in the class bodies apart from method definitions::
|
||||||
|
|
||||||
|
T = TypeVar('T')
|
||||||
|
S = TypeVar('S')
|
||||||
|
|
||||||
|
def a_fun(x: T) -> None:
|
||||||
|
# this is OK
|
||||||
|
y = [] # type: List[T]
|
||||||
|
# but below is an error!
|
||||||
|
y = [] # type: List[S]
|
||||||
|
|
||||||
|
class Bar(Generic[T]):
|
||||||
|
# this is also an error
|
||||||
|
an_attr = [] # type: List[S]
|
||||||
|
|
||||||
|
def do_something(x: S) -> S: # this is OK though
|
||||||
|
...
|
||||||
|
|
||||||
|
* A generic class definition that appears inside a generic function
|
||||||
|
should not use type variables that parameterize the generic function::
|
||||||
|
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
def a_fun(x: T) -> None:
|
||||||
|
|
||||||
|
# This is OK
|
||||||
|
a_list = [] # type: List[T]
|
||||||
|
...
|
||||||
|
|
||||||
|
# This is however illegal
|
||||||
|
class MyGeneric(Generic[T]):
|
||||||
|
...
|
||||||
|
|
||||||
|
* A generic class nested in another generic class cannot use the same
|
||||||
|
type variables, unless the inner class definition is inside a function.
|
||||||
|
|
||||||
|
|
||||||
Instantiating generic classes and type erasure
|
Instantiating generic classes and type erasure
|
||||||
----------------------------------------------
|
----------------------------------------------
|
||||||
|
|
||||||
|
@ -1297,11 +1383,11 @@ from ``UserId`` where ``int`` is expected. Examples::
|
||||||
|
|
||||||
num = UserId(5) + 1 # type: int
|
num = UserId(5) + 1 # type: int
|
||||||
|
|
||||||
``NewType`` accepts only one argument that shoud be a proper class,
|
``NewType`` accepts exactly two arguments: a name for the new unique type,
|
||||||
i.e., not a type construct like ``Union``, etc. The function returned
|
and a base class. The latter should be a proper class, i.e.,
|
||||||
by ``NewType`` accepts only one argument; this is equivalent to supporting
|
not a type construct like ``Union``, etc. The function returned by ``NewType``
|
||||||
only one constructor accepting an instance of the base class (see above).
|
accepts only one argument; this is equivalent to supporting only one
|
||||||
Example::
|
constructor accepting an instance of the base class (see above). Example::
|
||||||
|
|
||||||
class PacketId:
|
class PacketId:
|
||||||
def __init__(self, major: int, minor: int) -> None:
|
def __init__(self, major: int, minor: int) -> None:
|
||||||
|
|
Loading…
Reference in New Issue