Annotate or yes?

What are type annotations in Python?

By reading this article, I hope you are familiar with annotations in Python. But let me briefly remind you. They are needed in order to give some rigor to our dynamically typed language.

Duck typing

Duck typing

How it works in the IDE using PyCharm as an example

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

Hints in PyCharm

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.

What's under the hood?

In python, type annotations are read during the import stage and stored in the attribute __annotations__. Let's see what is in this attribute of our method custom_sum:

__annotations__ attribute

Attribute __annotations__

This attribute stores dictkey return which corresponds to the return type annotation that comes after ->.

To obtain annotations, typing provides a method get_type_hints.

Using the get_type_hints method

Using the get_type_hints method

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

Overheads?

Unfortunately, adding types to python code does not provide any performance gains. Only causes some overhead:

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

  2. Referencing types that have not yet been defined requires the use of string notations rather than actual types.

The first point is clear. I'll give you an example where the second point can cause us difficulties.

An example of a class where a method returns an instance of its class

An example of a class where a method returns an instance of its class

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

The approved PEP 563 “Postponed Evaluation of Annotations” reduced the time required to process type annotations at runtime. Type annotations are no longer evaluated at the time the function is defined, but are instead stored in the annotations in string form (without performing any calculations). To achieve this you need to do one import.

Import job

Import job

Thanks to import from __future__ import annotations you can see that the types have become simple strings, although they are not defined like quoted types. Initially, the plan was to make this behavior the default behavior (without importing anything). But the developers FastAPI And pydantic insisted that this part be optional since it breaks the operation of these libraries.

MyPy

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

test_file.py for testing MyPy

test_file.py for testing MyPy

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

MyPy's answer

MyPy's answer

Interesting Annotation Examples

I won't talk about the basic types, such as str, int etc. I will also omit the common types from the typing library by type List, Union, Optional because there is a lot of information about this.

Annotation *args **kwargs

You can set what types *args **kwargs should accept. The code below states that args only accepts string values, and kwargs only accepts numbers.

Example type hints for 8agrs **kwargs

Example type hints for 8agrs **kwargs

MyPy will throw the following error:

Error from MyPy

Error from MyPy

The essence of the error is that all unnamed arguments *args waiting type strwe are transmitting int.

Object is a subtype

If given 2 classes User And ProUserwhich inherits User. In this case, we can pass to the method that expects User type ProUser.

An example of working with subtypes

An example of working with subtypes

Answer from MyPy

Answer from MyPy

Called Arguments

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

Called Arguments

Called Arguments

Annotating Variables

Up to this point, we have only talked about annotations of function arguments and return values. In addition, you can annotate other variables.

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 you really want to specify types everywhere, you should take a closer look at another programming language.

Typing for Decorators

Often annotating decorators is not a good idea. They not only do not improve the reading of the code, but make what is happening more incomprehensible. Here's an example of a decorator annotation I found on the Internet:

Looks so-so, doesn't it?

Looks so-so, doesn't it?

So what's the bottom line?

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

If we talk about the philosophy of the language, it’s not about that, python is more about speed of development and ease of use. The abstract reveals itself in all its glory on large projects, when the overall reliability of the system is important to us. Tools like MyPy will tell us what we are doing wrong. Speaking about small quick projects or scripts, I would not use typing.

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

I myself can no longer help but use annotations, for me it has become a habit, for me it is generally a good practice in development. But I will not force my work colleagues to use types, but rather simply share the advantages of using them.

I learned my lesson at great cost: for small programs, dynamic typing is a good thing. But larger programs require a more disciplined approach.

Guido Van Rossum, Monty Python fan

Useful sources

Romaglio 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

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *