PEP: PEP stands for Python Improvement Proposal. It is a design document that describes new features for Python or its processes or environment. It also provides information for the Python community.
PEP — it is the primary mechanism for proposing major new features such as the Python web server gateway interface, gathering community information on issues, and documenting design decisions that have been implemented in Python.
Feature annotations — PEP 3107: PEP-3107 introduced the concept and syntax for adding arbitrary metadata annotations in Python. It was introduced in Python3, which was previously made using external libraries in Python 2.x
What are function annotations?
Function annotations — they are arbitrary Python expressions associated with different parts of the functions. These expressions are evaluated at compile time and have no life in the Python runtime. Python doesn’t attach any importance to these annotations. They take life when interpreted by third party libraries like Mypy.
The purpose of function annotations:
The benefits of function annotations can only be gained through third party libraries. The type of privileges depends on the type of library, for example
- Python supports dynamic typing and therefore there is no module for type checking. Annotations as
[def foo (a: ”int”, b: ”float” = 5.0) -" ”Int”]
(the syntax is detailed in the next section) can be used to gather information about the type of parameters and the return type of a function, in order to track the type change that occurs in the function. mypy — one such library.
- String-based libraries can be used by libraries to provide better compile-time reference messages regarding the functions of various methods, classes and modules.
- Annotations for simple parameters: the argument name is followed by ":" followed by an expression. The annotation syntax is shown below:
def foobar (a: expression, b: expression = 5):
- Annotations for redundant parameters: redundant parameters, for example, for * args and ** kwargs, allow you to pass an arbitrary number of arguments in a function call. The syntax for annotating such parameters is as follows:
def foobar (* args: expression, * kwargs: expression):
- Annotations for nested parameters: Nested parameters — A useful feature of Python 2x where a tuple is passed in when a function is called and auto-unpacking occurs. This feature has been removed in Python 3x and must be manually unpacked. The annotation is after the variable, not after the tuple, as shown below.
def foobar ((a: expression, b: expression), (c: expression, d: expression)):
- Annotated return type: The annotated return type is slightly different from the annotated function arguments. & # 39; -" & # 39; followed by an expression followed by & # 39;: & # 39 ;. The return type annotation syntax is shown below:
def foobar (a: expression) -" expression:
- Using & # 39; mypy & # 39 ;: & # 39; mypy & # 39; — it is an external library that provides static type checking using function annotations.
Download Mypy for Python 2xpip install mypy
Python 3x
pip install git + git: //github.com/JukkaL/mypy.git
Example 1:
# Line slice function that returns a string from start index to end index.
def
slice
(string:
str
, start:
int
, end:
int
)
-
"
str
:
return
string [start: end]
slice
([
1
,
2
,
3
,
4
,
5
],
2
,
4
)
Save the above code as example.py and run the following command after installing mypy. Make sure you are in the directory where you saved the file.
mypy example.py
You get the following result.
- Things are a little different when decorators are involved.
Example 2 (part a): checking the types of parameters of collapsed functions & # 39; gift_func & # 39; and & # 39; wrapped & # 39;def
wrapping_paper (func):
def
wrapped (gift:
int
):
return
’ I got a wrapped up {} for you’
.
format
(
str
(func (gift)))
return
wrapped
@ wrapping_paper
def
gift_func (giftna me:
int
):
return
giftname
print
(gift_func (
’gtx 5000’
))
At first it seems that passing a string as an argument will return an error, since the required data type is — it’s an int annotated with gift_func and wrapped. mypy does not set type checking on collapsed function parameters, however, the type checking in the decorator and the return type of collapsed functions can be checked. Therefore, the following result can be expected from the above code.
- Example 2 (part b): checking the types of parameters of the decorator & # 39; wrapping_paper & # 39 ;.
def
wrapping_paper (func:
str
):
def
wrapped (gift:
int
):
return
’I got a wrapped up {} for you’
.
format
(
str
(func (gift)))
return
wrapped
@ wrapping_paper
def
gift_func (giftname:
int
):
return
giftname
print
(gift_func (
’ gtx 5000’
))
Now you get the following result.
- Example 2 (part c): checking the return types of & # 39; gift_func & # 39; and & # 39; wrapped & # 39;
# Let’s assume we want so that the return type is int
from
typing
import Callable
def
wrapping_paper (func):
def
wrapped (gift)
-
"
int
:
return
’I got a wrapped up {} for you’
.
format
(
str
(func (gift )))
return
wrapped
@ wrapping_paper
def
gift_func (giftname)
-
"
int
:
return
giftname
print
(gift_func (
’gtx 5000’
))
You will get the following result.
- Example 2 (part d) Checking the return type of a wrapper function & # 39; wrapping_paper & # 39;
# Let’s assume we want so that the return type is int
from
typin g
import
Callable
def
wrapping_paper (func)
-
"
int
:
def
wrapped (gift):
return
’I got a wrapped up {} for you’
.
format
(
str
(func (gift )))
return
wrapped
@ wrapping_paper
def
gift_func (giftname):
return
giftname
p rint
(gift_func (
’gtx 5000’
))
You will get the following result
Functional annotation syntax
They are like the optional parameters that follow the parameter name.
- Note . The word "expression" mentioned below can be the type of parameters to be passed, or comment, or any arbitrary string that can be used in a meaningful way by external libraries.
grammar
decorator : ’@’ name_ [’(’ [arglist] ’)’] NEWLINE decorators : decorator + funcdef : [decorators] ’def’ NAME parameters [’-"’] ’:’ suite parameters : ’(’ [typedarglist] ’)’ typedarglist : ( (tfpdef [’=’ test] ’,’) * (’*’ [tname] (’,’ tname [’=’ test]) * [’,’ ’**’ tname] | ’**’ tname) | tfpdef [’=’ test (’,’ tfpdef [’=’ test]) * [’,’]]) tname : NAME [’:’ test] tfpdef : tname | ’(’ tfplist ’)’ tfplist : tfpdef (’,’ tfpdef) * [’,’]
Grammar visualization: parse tree generated from the above grammar to provide a better visualization of function syntax and Python annotations.
Sample Code
Below the code will clarify the fact that function annotations are not evaluated at runtime. The code prints the Fibonacci series up to the "n" positions.
|
Output: [1, 1, 2, 3, 5]
Note: Function annotations are only supported in Python 3x.
Access to function annotations
1. Using "__annotations__". The function annotations in the above code are accessed through the special attribute "__annotations__". It outputs a dictionary with the special key return and other keys with the names of the annotated arguments. The following code will print annotations.
|
Output: {’return’:’ list’, ’n’:’ int’, ’output’:’ list’}
2. Using the standard module & # 39; pydoc & # 39; : & # 39; pydoc & # 39; — it is a standard python module that returns documentation inside a python module (if any). It has a special method help () that provides an interactive shell for getting help for any keyword, method, class, or module. & # 39; help () & # 39; can be used to access function annotations. The figure below shows the function annotations in the above Fibonacci series code. Module name — "Fib.py".
3. Using the standard inspect module : The inspect module provides several useful functions that help you get information about living objects, such as modules, classes, methods, functions, callbacks, frame objects, and code objects. We can use the getfullargspec method of the module to get full information about the function, which will contain annotations.
|
Output: FullArgSpec (args = [’ n’, ’output’], varargs = None, varkw = None, defaults = ([],), kwonlyargs = [], kwonlydefaults = None, annotations = {’ output’: ’list’,’ return’: ’list ’,’ n’: ’int’})
Using function annotations
This article is courtesy of Anmol Chachra . If you are as Python.Engineering and would like to contribute, you can also write an article using contribute.python.engineering or by posting an article contribute @ python.engineering. See my article appearing on the Python.Engineering homepage and help other geeks.
Please write in comments if you find anything wrong or if you’d like to share more information on the topic discussed above.