Annotate or so? / Hebrew

Annotate or so? / Hebrew

What are type annotations in Python?

By reading this article, I hope you are familiar with instructions in Python. But still, I will briefly remind you. They are needed to give some rigor to our dynamically typed language.

Duck typing

How it works in the IDE on the example of PyCharm

Already at the development stage, we can see that we are using methods that are wrong if their author wrote annotations to the code.

Hints in PyCharm

In the example, the function argument first expects a numeric value, and we pass a string. Thanks to modern code editors, we can avoid potential errors.

And what’s under the hood?

In python, type instructions are read at the import stage and stored in an attribute __annotations__. Let’s see what is in this attribute of our method custom_sum:

Attribute __annotations__

Stored in this attribute dictthe key return which is matched by the return type annotation that follows ->.

typing provides a method to receive instructions get_type_hints.

Using the get_type_hints method

As you can see, the values ​​in the dictionary are real python classes.

Overhead?

Unfortunately, adding types to python code doesn’t provide any performance gains. Just causes some overhead:

  1. Importing modules takes more time and memory (because you need to read the annotations and write them in the attribute __annotations__);

  2. References to types that are not yet defined require the use of string notations, not actual types.

Everything is clear with the first point. I will give an example when the second point can cause us difficulties.

An instance of a class where the method returns an instance of the class

You can see the “preemptive link” problem. Our class wants to return an instance of itself in one of its methods, but cannot do so because the class object is not yet defined until Python has finished computing its body. In this case, we are forced to write the return value as a string. Because of this behavior, the instructions were processed at the time the functions and modules were defined, which was computationally expensive (the program must understand what this line means).

Approved PEP 563 “Postponed Evaluation of Annotations” reduced the time needed to process type annotations at runtime. Type instructions are no longer evaluated at the time of function definition, instead they are stored in the instructions in string form (without doing any calculations). To achieve this, you need to make one import.

Import work

Thanks to imports from __future__ import annotations you can see that the types have become simple strings, although not defined like quoted types. The original plan was to make this behavior the default behavior (without importing anything). But developers FastAPI and pydantic insisted that this part be optional because it breaks the way these libraries work.

MyPy

MyPy is required for static type checking in Python. This library checks our instructions and how we use them. I will give a very small example, you can find out more at the link:

test_file.py to test MyPy

When calling the function test_func we mistakenly pass instead str type int. MyPy helps us understand that we are doing something wrong:

MyPy’s answer

Interesting examples of annotations

I won’t talk about basic types like str, int etc. I will also omit common types from the typing library by type Letter, Union, Optional because there is a lot of information about it.

Abstract *args **kwargs

You can set which types *args **kwargs should take. The code below specifies that args only takes string values ​​and kwargs only takes numbers.

Example of type hints for 8agrs **kwargs

MyPy will throw the following error:

Error from MyPy

The gist of the error is that all unnamed arguments *args waiting for the type strwe will pass it on int.

An object is a subtype

If 2 classes are given User and ProUserwho inherits User. In this case, we can pass to the awaiting method User type ProUser.

An example of working with subtypes

Answer from MyPy

Summoned arguments

Also we can annotate a function argument even if it is another function, thanks to Callable from the module typing. You can also use this tool to specify what a function expects and what it returns. In our case, the method bar accepts str and returns None.

Summoned arguments

Annotation of variables

Up to this point, we’ve only talked about function argument annotations and return values. In addition, variables can be annotated.

Speaking for myself, I don’t use variable annotations. Because typing functions helps us work with interfaces, while working with variables only increases development time. If there is a strong desire to specify types everywhere, it is worth looking at another programming language.

Typing for decorators

Annotating decorators is often not a good idea. Not only do they not improve the readability of the code, they make it unclear what is going on. I will give an example of a decorator’s manual found on the Internet:

It looks pretty, doesn’t it?

So what is the result?

Unfortunately, in Python, typing does not provide any performance gains, only potential slowdowns and increased memory consumption. Also, in order to use it correctly, you need to spend some time to figure out what is for what.

If we talk about the philosophy of the language – it is not about that, python is more about the speed of development and ease of use. The annotation reveals itself in all its glory in large projects, when the overall reliability of the system is important to us. Such tools as MyPy will tell us what we are doing wrong. Speaking about small projects “on the fly” or scripts – I would not use typing.

It is interesting to note that not all core Python developers use Type hints in their code.

I myself can no longer avoid using annotations, it has become a habit for me, for me it is usually a good tone in development. But I will not force my work colleagues to use types, but rather just share the advantages of their use.

I learned a lesson with a heavy price: for small programs, dynamic typing is a boon. But larger programs require a disciplined approach.

Guido Van Rossum, a fan of Monty Python

Useful sources

Romal L. PYTHON. To the heights of mastery / 2nd edition / Moscow: DMK Press, 2022. – 897

MyPy documentation – URL: https://mypy.readthedocs.io/en/stable/

PEP 484 – Type Hints – URL: https://peps.python.org/pep-0484/

PEP 483 – The Theory of Type Hints – URL: https://peps.python.org/pep-0483/

typing – Support for type hints – URL: https://docs.python.org/3/library/typing.html

Related posts