Skip to content

Commit

Permalink
Merge pull request #3 from ilevkivskyi/master
Browse files Browse the repository at this point in the history
Update according to latest discussions
  • Loading branch information
Philip House authored Aug 30, 2016
2 parents e651357 + 1b9fad1 commit bb17361
Showing 1 changed file with 55 additions and 23 deletions.
78 changes: 55 additions & 23 deletions pep-0526.txt
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ a core part of the language.
Non-goals
*********

While the proposal is accompanied by an addition of ``inspect.getannotations``
While the proposal is accompanied by an extension of ``typing.get_type_hints``
standard library function for runtime retrieval of annotations, the variable
annotations are not designed for runtime type checking. Third party packages
would have to be developed to implement such functionality.
Expand All @@ -99,8 +99,17 @@ easy way to specify the structured type metadata for third party tools.
Specification
=============

*** big key concepts, not quite sure what the best way to organize this would
be, or if they deserve their own sections ***
Type annotation could be added to an assignment statement or to a simple
name indicating the desired type of the annotation target to a third
party type checker::

my_var: int
my_var = 5 # Passes type check.
other_var: int = 'a' # Flagged as error by type checker,
# but OK at runtime.

Below we specify the semantics of type annotations for type checkers
in different contexts and their runtime effects.

Variable Annotations
********************
Expand All @@ -119,7 +128,7 @@ assigned in conditional branches::
else:
sane_world = False

Note that, although this syntax does allow tuple packing, it does *not* allow
Note that, although the syntax does allow tuple packing, it does *not* allow
one to annotate the types of variables when tuple unpacking is used::

# Tuple packing with variable annotation syntax
Expand Down Expand Up @@ -231,14 +240,20 @@ any valid assignment target::
class Cls:
pass

c = Cls
c.x: int = 0 # Annotates ``c.x`` with ``int``..
c = Cls()
c.x: int = 0 # Annotates c.x with int.
c.y: int # Invalid syntax: no initial value was specified!

d = {}
d['a']: int = 0 # Annotates ``d['a']`` with ``int``.
d['a']: int = 0 # Annotates d['a'] with int.
d['b']: int # Invalid again.

Note that even ``(my_var)`` is considered an expression, not a simple name.
Consequently::

(x): int # Invalid syntax
(x): int = 0 # OK

Where annotations aren't allowed
********************************

Expand All @@ -247,10 +262,15 @@ It's illegal to attempt to annotate ``global`` and ``nonlocal``::
def f():
global x: int # SyntaxError

def g():
x: int # Also a SyntaxError
global x

The reason is that ``global`` and ``nonlocal`` don't own variables;
therefore, the type annotations belong in the scope owning the variable.

In addition, you cannot annotate variable used in a ``for`` or ``with``
Only single assignment targets and single right hand side values are allowed.
In addition, one cannot annotate variables used in a ``for`` or ``with``
statement; they can be annotated ahead of time, in a similar manner to tuple
unpacking::

Expand All @@ -270,12 +290,13 @@ Changes to standard library and documentation
instances. This restriction is ensured by static checkers,
but not at runtime.

- Function ``getannotations`` is added to the ``inspect`` module that is used
to retrieve annotations at runtime from modules, classes, and functions.
- Function ``get_type_hints`` in the ``typing`` module will be extended,
so that one can retrieve type annotations at runtime from modules
and classes in addition to functions.
Annotations are returned as a dictionary mapping from variable, arguments,
or attributes to their type hints. For classes it returns
``collections.ChainMap`` constructed from annotations in method
resolution order of that class.
or attributes to their type hints with forward refs evaluated.
For classes it returns ``collections.ChainMap`` constructed from
annotations in method resolution order of that class.

- Recommended guidelines for using annotations will be added to the
documentation, containing a pedagogical recapitulation of specifications
Expand All @@ -287,11 +308,9 @@ Changes to standard library and documentation
Runtime effects of type annotations
===================================

As stated under "Variable Annotations", annotating a local variable will cause
Annotating a local variable will cause
the interpreter to treat it as a local, even if it was never assigned to.

If a variable annotation is for a local variable, the annotation will not be
evaluated::
Annotations for local variables will not be evaluated::

def f():
x: NonexistentName # No error.
Expand All @@ -317,12 +336,11 @@ from names to evaluated annotations. Here is an example::
# prints: {'players': typing.Dict[str, __main__.Player]}

The recommended way of getting annotations at runtime is by using
``inspect.getannotations`` function; as with all dunder attributes,
``typing.get_type_hints`` function; as with all dunder attributes,
any undocummented use of ``__annotations__`` is subject to breakage
without warning::

from typing import Dict, ClassVar
from inspect import getannotations
from typing import Dict, ClassVar, get_type_hints
class Starship:
hitpoints: int = 50
stats: ClassVar[Dict[str, int]] = {}
Expand All @@ -331,12 +349,12 @@ without warning::
def __init__(self, captain: str) -> None:
...

assert getannotations(Starship) == {'hitpoints': int,
assert get_type_hints(Starship) == {'hitpoints': int,
'stats': ClassVar[Dict[str, int]],
'shield': int,
'captain': str}

assert getannotations(Starship.__init__) == {'captain': str,
assert get_type_hints(Starship.__init__) == {'captain': str,
'return': None}

Note that if annotations are not found statically, then the
Expand Down Expand Up @@ -368,7 +386,15 @@ preferred use of annotations.


Rejected proposals and things left out for now
=============================================
==============================================

- **Do not introduce variable annotations at all:**
Variable annotations have *already* been around for almost two years
in the form of type comments. They are extensively used by third
party type checkers (mypy, pytype, etc) and by projects using the
type checkers. However, the comment syntax has many downsides
listed in Rationale. This PEP is not about the need for type
annotations, it is about what should be the syntax for such annotations.

- **Introduce a new keyword:**
First, choice of a good keyword is hard,
Expand Down Expand Up @@ -436,6 +462,12 @@ Rejected proposals and things left out for now
declarations together in the class makes it easier to find them,
and helps a first-time reader of the code.

- **Use syntax** ``x: class t = v`` **for class variables:**
This will require a more complicated parser and will confuse simple
minded syntax highlighters. Anyway we need to have ``ClassVar`` to
store class variables to ``__annotations__``, so that it was decided
to go with a simpler syntax.

- **Forget about** ``ClassVar`` **altogether:**
This was proposed since mypy seems to be getting along fine without a way
to distinguish between class and instance variables. But a type checker
Expand Down

0 comments on commit bb17361

Please sign in to comment.