Tuesday, November 5, 2019

Python 3.7.5 : About PEP 3107.

The PEP 3107 introduces a syntax for adding arbitrary metadata annotations to Python functions.
The function annotations refer to syntax parameters with an expression.
def my_function(x: expression, y: expression = 5):
...
For example:
>>> def show(myvar:np.float64):
...     print(type(myvar))
...     print(myvar)
... 
>>> show(1.1)

1.1
>>> def files(filename: str, dot='.') -> list:
...     print(filename)
...     print(type(filename))
... 
>>> files('file.txt')
file.txt

>>> print(files.__annotations__)
{'filename': , 'return': }
>>> print(show.__annotations__)
{'myvar': }
...
You can see the annotation syntax with a dictionary called __annotations__ as an attribute on your functions.
This lets you rewrite Python 3 code with function annotations to be compatible with both Python 3 and Python 2.
Type hints are a specialization of function annotations, and they can also work side by side with other function annotations.
Annotations have no standard meaning or semantics.
There are several benefits to the annotations:
  • if you rename an argument, the documentation docstring version may be out of date and is easier to see if an argument is not documented;
  • is no need to come up with a special format of argument because the annotations attribute provides a direct, standard mechanism of access;
Let's see one example using type aliases:

>>> Temperature = float
>>> def forecast(local_temperature: Temperature) -> str:
...     print(local_temperature)
... 
>>> forecast(13.1)
13.1
...
I can create multiple annotations:

>>> def div(a: dict(type=float, help='the dividend'), b: dict(type=float, help='this <> 0)') ) -> 
dict(type=float, help='the result of dividing a by b'):
...     return a / b
... 
>>> div(3,4)
0.75
...
Annotations for excess parameters like *args and **kwargs, allow arbitrary number of arguments to be passed in a function call.
See example with my_func:
def my_func(*args: expression, *kwargs: expression):
...
Annotations combine well with decorators to provide input to a decorator, and decorator-generated wrappers are a good place to put code that gives meaning to annotations, but this is another issue.