PEP 0526 next round of edits (#72)
* setting up pep-0526 headers * Some work on PEP 526 abstract and rationale * adding info about annotations specs * PEP 526 updates * PEP 526 updates * adding section about instance variables inside methods * Change declare/declaration -> annotate/annotation. * Add notice for reviewers.
This commit is contained in:
parent
82fbafb118
commit
b9e9bee341
174
pep-0526.txt
174
pep-0526.txt
|
@ -1,5 +1,5 @@
|
|||
PEP: 526
|
||||
Title: Variable Declaration Syntax
|
||||
Title: Syntax for Variable and Attribute Annotations
|
||||
Version: $Revision$
|
||||
Last-Modified: $Date$
|
||||
Author: Ryan Gonzalez <rymg19@gmail.com>, Philip House <phouse512@gmail.com>, Guido van Rossum <guido@python.org>
|
||||
|
@ -9,6 +9,16 @@ Content-Type: text/x-rst
|
|||
Created: 09-Aug-2016
|
||||
Python-Version: 3.6
|
||||
|
||||
Notice for Reviewers
|
||||
====================
|
||||
|
||||
This PEP is not ready for review. We're merely committing changes
|
||||
frequently so we don't end up with a huge merge conflict. For minor
|
||||
textual nits please use https://github.com/python/peps/pull/72. For
|
||||
discussion about contents, please refer to
|
||||
https://github.com/python/typing/issues/258 (but please be patient, we
|
||||
know we're way behind addressing all comments).
|
||||
|
||||
Abstract
|
||||
========
|
||||
|
||||
|
@ -22,7 +32,7 @@ type comments::
|
|||
class Cls:
|
||||
my_class_attr = True # type: bool
|
||||
|
||||
This PEP aims at adding syntax to Python for declaring the types of variables and
|
||||
This PEP aims at adding syntax to Python for annotating the types of variables and
|
||||
attributes, instead of expressing them through comments::
|
||||
|
||||
a: List[int] = []
|
||||
|
@ -36,10 +46,10 @@ Rationale
|
|||
Although type comments work well, the fact that they're expressed through
|
||||
comments has some downsides:
|
||||
|
||||
- Text editors often highlight comments differently from type declarations.
|
||||
- There isn't a way to declare the type of an undefined variable; you need to
|
||||
- Text editors often highlight comments differently from type annotations.
|
||||
- There isn't a way to annotate the type of an undefined variable; you need to
|
||||
initialize it to ``None`` (e.g. ``a = None # type: int``).
|
||||
- Variables declared in a conditional branch are difficult to read::
|
||||
- Variables annotated in a conditional branch are difficult to read::
|
||||
|
||||
if some_value:
|
||||
my_var = function() # type: Logger
|
||||
|
@ -55,3 +65,157 @@ comments has some downsides:
|
|||
|
||||
The majority of these issues can be alleviated by making the syntax a core part of
|
||||
the language.
|
||||
|
||||
Specification
|
||||
=============
|
||||
|
||||
*** big key concepts, not quite sure what the best way to organize this would be,
|
||||
or if they deserve their own sections ***
|
||||
|
||||
Normal Variable Typing
|
||||
**********************
|
||||
|
||||
The types of locals and globals can be annotated as follows::
|
||||
|
||||
some_number: int # variable without default
|
||||
some_list: List[int] = [] # variable with default
|
||||
|
||||
Being able to omit the initial value allows for easier typing of variables
|
||||
assigned in conditional branches::
|
||||
|
||||
sane_world: bool
|
||||
if 2+2 == 4:
|
||||
sane_world = True
|
||||
else:
|
||||
sane_world = False
|
||||
|
||||
Note that, although this 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
|
||||
t: Any = (1, 2, 3)
|
||||
|
||||
# Tuple unpacking with type comments
|
||||
x, y, z = t # type: int, int, int
|
||||
|
||||
# Tuple unpacking with variable annotation syntax
|
||||
x: int
|
||||
y: int
|
||||
z: int
|
||||
x, y, z = t
|
||||
|
||||
Omitting a default value leaves the variable uninitialized::
|
||||
|
||||
a: int
|
||||
print(a) # raises NameError
|
||||
|
||||
However, annotating a local variable will cause the interpreter to always make
|
||||
it a local::
|
||||
|
||||
def f():
|
||||
a: int
|
||||
print(a) # raises UnboundLocalError
|
||||
# Commenting out the `a: int` makes it a NameError!
|
||||
|
||||
as if the code were::
|
||||
|
||||
def f():
|
||||
if False: a = 0
|
||||
print(a) # raises UnboundLocalError
|
||||
|
||||
|
||||
Class Variable Typing
|
||||
*********************
|
||||
|
||||
Adding variable types allow for us annotate the types of instance variables in class
|
||||
bodies. In particular, the value-less notation (`a: int`) allows us to annotate
|
||||
instance variables that should be initialized in `__init__` or `__new__`. The
|
||||
proposed syntax looks as follows::
|
||||
|
||||
class Starship:
|
||||
captain: str # instance variable without default
|
||||
damage: int = 0 # instance variable with default
|
||||
stats: class Dict[str, int] = {} # class variable with initialization
|
||||
|
||||
|
||||
Duplicate annotations
|
||||
*********************
|
||||
|
||||
Any duplicate type annotations will be ignored::
|
||||
|
||||
a: int
|
||||
a: int # Doesn't do anything.
|
||||
|
||||
The Python compiler will not validate the type expression, and leave it to
|
||||
the type checker to complain. The above code will be allowed by the
|
||||
compiler at runtime.
|
||||
|
||||
Where annotations aren't allowed
|
||||
********************************
|
||||
|
||||
It's illegal to attempt to annotate ``global`` and ``nonlocal``::
|
||||
|
||||
def f():
|
||||
global x: int # SyntaxError
|
||||
|
||||
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``
|
||||
statement; they must be annotated ahead of time, in a similar manner to tuple
|
||||
unpacking::
|
||||
|
||||
a: int
|
||||
for a in my_iter:
|
||||
f: MyFile
|
||||
with myfunc() as f:
|
||||
# ...
|
||||
|
||||
Capturing Types at Runtime
|
||||
**************************
|
||||
|
||||
In order to capture variable types that are usable at runtime, we store the
|
||||
types in `__annotations__` as dictionaries at various levels. At each level (for
|
||||
example, global), the types dictionary would be stored in the `__annotations__`
|
||||
dictionary for that given level. Here is an example for both global and class
|
||||
level types::
|
||||
|
||||
# print global type annotations
|
||||
players: Dict[str, Player]
|
||||
print(__annotations__)
|
||||
|
||||
# print class type annotations
|
||||
class Starship:
|
||||
hitpoints: class int = 50
|
||||
stats: class Dict[str, int] = {}
|
||||
shield: int = 100
|
||||
captain: str # no initial value
|
||||
print(Starship.__annotations__)
|
||||
|
||||
A note about locals -- the value of having annotations available locally does not
|
||||
offset the cost of having to create and populate the annotations dictionary on
|
||||
every function call.
|
||||
|
||||
These annotations would be printed out from the previous program as follows::
|
||||
|
||||
{'players': Dict[str, Player]}
|
||||
|
||||
{'hitpoints': ClassVar[int],
|
||||
'stats': ClassVar[Dict[str, int]],
|
||||
'shield': int,
|
||||
'captain': str
|
||||
}
|
||||
|
||||
Mypy supports allowing `# type` on assignments to instance variables and other things.
|
||||
In case you prefer annotating instance variables in `__init__` or `__new__`, you can
|
||||
also annotate variable types for instance variables in methods. Despite this,
|
||||
`__annotations__` will not be updated for that class.
|
||||
|
||||
Backwards Compatibility
|
||||
=======================
|
||||
|
||||
|
||||
Copyright
|
||||
=========
|
||||
|
||||
This document has been placed in the public domain.
|
||||
|
|
Loading…
Reference in New Issue