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.
|
||||
|
||||
|
||||
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
|
||||
----------------------------------------------
|
||||
|
||||
|
@ -1297,11 +1383,11 @@ from ``UserId`` where ``int`` is expected. Examples::
|
|||
|
||||
num = UserId(5) + 1 # type: int
|
||||
|
||||
``NewType`` accepts only one argument that shoud be a proper class,
|
||||
i.e., not a type construct like ``Union``, etc. The function returned
|
||||
by ``NewType`` accepts only one argument; this is equivalent to supporting
|
||||
only one constructor accepting an instance of the base class (see above).
|
||||
Example::
|
||||
``NewType`` accepts exactly two arguments: a name for the new unique type,
|
||||
and a base class. The latter should be a proper class, i.e.,
|
||||
not a type construct like ``Union``, etc. The function returned by ``NewType``
|
||||
accepts only one argument; this is equivalent to supporting only one
|
||||
constructor accepting an instance of the base class (see above). Example::
|
||||
|
||||
class PacketId:
|
||||
def __init__(self, major: int, minor: int) -> None:
|
||||
|
|
Loading…
Reference in New Issue