Within PEP 3107 you can find the original PEP(Python Enhancement Proposals) for annotations of funcion parameters and return values.
This proposal that has been accepted is unfortunatelly only for Python3 and ongoing releases. Python2 out of the box backward compatibility is not possible.
Yet you can create some backward compatibility for those annotations if you need to.
Check out what this annotations are all about!
To The Point
Annotations
In other languages you have types. You expressly define your variable types, function return types and parameters types.
In Python 2 you could not do that (it would raise with SyntaxError) and frankly speaking you did not expect to do that.
In Python 3 you can use annotations to simulate defining function and variable types.
Here is example:
def greeting(name: str) -> str:
return 'Hello ' + name
So basically you have created a function that in python2 would look like this:
def greeting(name):
return 'Hello ' + name
But annotations gives you opportunity to check what type of output and parameter types you have within this function:
greeting.__annotations__
Unfortunatelly or fortunatelly it does not do anything else - So if you make annotations but you do not follow it - it will not raise it.
We can change that with decorator that will check that:
def decorator_annotation_for_return(function_wrapped):
def wrapper(*args, **kwargs):
annotations = function_wrapped.__annotations__
output = function_wrapped(*args, **kwargs)
returned_type = annotations.get('return')
if returned_type:
assert type(output) == returned_type
return output
return wrapper
Example of usage for this decorator:
@decorator_annotation_for_return
def greetings(name: str) -> str:
return "Hello " + name
print(greetings("Anselmos"))
# This will fail:
@decorator_annotation_for_return
def greetings_failing(name: str) -> str:
return 1
greetings_failing("A")
You can also create a parameter types checker with decorators, but in order for it to work properly you would need to use **kwargs
- which means you need to expressively name arguments for function.
Check out example of that decorator:
def decorator_annotation_parameters(function_wrapped):
def wrapper(*args, **kwargs):
annotations = function_wrapped.__annotations__
output = function_wrapped(*args, **kwargs)
returned_type = annotations.get('return')
for kwarg in kwargs:
kwarg_type = annotations.get(kwarg)
assert type(kwargs[kwarg]) == kwarg_type
if returned_type:
assert type(output) == returned_type
return output
return wrapper
@decorator_annotation_parameters
def greetings_parameter(name: str) -> str:
return name
print(greetings_parameter(name=1))
It may need some tweaking to have better readiness but it works.
Also check out the suggested in pep Use Cases.
Snippets
def function(parameter: annotation_parameter_type) -> annotation_parameter_type:
pass
def decorator_annotation_parameters(function_wrapped):
def wrapper(*args, **kwargs):
annotations = function_wrapped.__annotations__
output = function_wrapped(*args, **kwargs)
returned_type = annotations.get('return')
for kwarg in kwargs:
kwarg_type = annotations.get(kwarg)
assert type(kwargs[kwarg]) == kwarg_type
if returned_type:
assert type(output) == returned_type
return output
return wrapper
Acknowledgements
Auto-promotion
Related links
- PEP 3107 -- Function Annotations | Python.org
- PEP 526 -- Syntax for Variable Annotations | Python.org
- GitHub - PythonCharmers/python-future: Easy, clean, reliable Python 2/3 compatibility
- PEP 484 -- Type Hints | Python.org
Thanks!
That's it :) Comment, share or don't - up to you.
Any suggestions what I should blog about? Post me a comment in the box below or poke me at Twitter: @anselmos88.
See you in the next episode! Cheers!
Comments
comments powered by Disqus