Background
PEP 3107
One of the innovations in Python 3.0 was the introduction of a new syntax that allows you to store arbitrary metadata of arguments and return values โโof functions as annotations. The innovation was described in PEP 3107 .
According to him, the function annotations are:
completely optional to use;
a way to associate arbitrary Python expressions with various parts of a function at the time the interpreter defines it.
For Python, annotations are of no interest and are not used in any way. It just makes annotations available to third party tools.
These tools can use them as they please. For example, to add additional descriptions to the function arguments:
def func(arg: "arg description"):
pass
Or to provide type checking for arguments and return values โโof functions:
def func(arg: int) -> bool:
pass
PEP 3107 emphasized that the examples above are by themselves meaningless. They only make sense for third-party tools such as static analyzers, etc.
Annotations can be accessed using a special dictionary __annotations__
:
def func(arg: "arg description"):
pass
print("Annotations: ", func.annotations)
Let's run the script:
$ python ./example.py
Annotations: {"arg": "arg description"}
PEP 484 - Type Hints
PEP 3107 deliberately did not define the semantics of function annotations and how to use them.
, . Python .
Python 3.5 PEP 484, . , .
PEP 484 typing
, .
, ( mypy PEP 484), , __annotations__
. .
PEP. , , typing
, Python. , Python 3.6 Dict[str, Tuple[S, T]]
, Python 3.5 . Python 3.6, - Python 3.5.
, , (forward reference).
class Tree:
def __init__(self, height: int, children: List[Tree]):
self.height = height
self.children = children
, . , . Tree
, , NameError
name 'Tree' is not defined
.
, , , , . PEP 484 :
class Tree:
def __init__(self, height: int, children: List['Tree']):
self.height = height
self.children = children
, , eval
Python.
, , :
Python;
, ;
, , .
: , , , .
PEP 563 -
PEP 563 :
( );
, , .
:
class Tree:
def __init__(self, height: int, children: List[Tree]):
self.height = height
self.children = children
, PEP . , :
class Tree:
def __init__(self, height: "int", children: "List[Tree]"):
self.height = height
self.children = children
, , __annotations__
, .
, , .
, Python, typing.get_type_hints
.
:
Python;
, , .
PEP Python 3.7, , from __future__ import annotations
. Python 3.10.
, PEP 563, . . , Python, typing.get_type_hints
.
, , . , typing.get_type_hints
, , , .
, (, , ..). : , , typing.get_type_hints
.
"" Python 3.10 Pydantic, issue Github, , Pydantic . , , , Pydantic FastAPI.
, , Python . PEP 649.
issue, Python Pydantic FastAPI . , - .
Python , Python 3.11. . PEP 649 Python 3.11.
PEP 649 -
Python 3.9 :
, (PEP 484);
(PEP 563).
, . , , , .
PEP 649 , . , , .
, , . , __annotations__
, . __annotations__
, , , . __annotations__
, , .
, , , . . , , __annotations__
.
, PEP 563.
:
def foo(x: int = 3, y: MyType = None) -> float:
...
class MyType:
...
foo_y_type = foo.annotations['y']
__annotations__
, . , __annotations__
.
Python 3.9 , , . , , :
annotations = {'x': int, 'y': MyType, 'return': float}
def foo(x = 3, y = "abc"):
...
foo.annotations = annotations
class MyType:
...
foo_y_type = foo.annotations['y']
, . , PEP 563 :
annotations = {'x': 'int', 'y': 'MyType', 'return': 'float'}
def foo(x = 3, y = "abc"):
...
foo.annotations = annotations
class MyType:
...
foo_y_type = foo.annotations['y']
, . , :
class function:
# __annotations__ "
# ", .
@property
def __annotations__(self):
return self.__co_annotations__()
# ...
def foo_annotations_fn():
return {'x': int, 'y': MyType, 'return': float}
def foo(x = 3, y = "abc"):
...
foo.co_annotations = foo_annotations_fn
class MyType:
...
foo_y_type = foo.annotations['y']
, , , , foo_annotations_fn()
. , foo.__annotations__
, , MyType
. , , foo_y_type
- MyType
- , MyType
, .
At the moment, the problem of forward links remains unresolved. A solution that is suitable for static code analysis is completely unsuitable for use at runtime. The community of developers using Pydantic and FastAPI continues to grow ( FastAPI ranks third among Python web frameworks) and Python developers will have to take their opinion into account when developing annotations.
Despite some uncertainty, I think there will be even more ways to use annotations at runtime in the future. Thanks for reading!