Annotations in Python
The data types of variables, function parameters, and function return types are described via the annotations which are the arbitrary Python phrases.
In order to provide the efficient and time-saving features like syntax suggestions, data type hinting in IDEs, data type checking, robotic or AI-driven documentation creation, and auto-completion of code, annotations strive to make the source code more accessible and understandable.
The function and variable annotations are the two types of annotations available in Python. With the use of pertinent examples, we will discuss both forms of Python annotations in this post.
What Are Variable Annotations?
Python uses expressions called variable annotations to describe the data types of variables in more depth. The syntax for variable annotations is given in the following:
The expressions for annotations are prefixed with a colon “or:” and placed between the variable name and initial value. To further understand the concept, refer to the following Python code. We used the built-in Python data types for expressions in the following example. The attached image demonstrates the overall sample code:
Here is the result produced by the previous code shown:
Strings can also be used to describe the variables in place. This is displayed in the code as you can see in the following:
Attached is the output:
To access every annotation, utilize the “__annotations___” attribute. This property is a dictionary with variables as keys and annotation expressions as values. The functions are not covered by this attribute. It only provides information about the variables. For this, see the following Python code:
The outcome of utilizing the “_annotations_” in the Python code is seen in the following:
We only talked about the simple data types thus far, including the int, float, and str. Let’s now look at how to create the annotation expressions for more complicated data types like lists, tuples, sets, lists of objects, etc. We’ll make use of the type module for this.
The standard library of Python includes the type module. With the help of an example, let’s learn how to apply it to the complex data types. For this, see the following Python code:
The following is the result:
The generic forms of list, tuple, and set are represented by the classes List, Tuple, and Set in the type module. Other generic classes exist in addition to these three including Dict, FrozenSet, DefaultDict, and OrderedDict.
You can employ these generic classes to give the variables the annotation expressions. Following the classes are the  bracketed pointers to the other generic classes, string descriptions, primitive data types, or classes from the same module.
This article’s next section will discuss how to use them to formulate the function expressions.
What Are Function Annotations?
In PEP-3107, function annotations are outlined. The primary goal is to establish a uniform method for connecting the information to the function arguments and return values. Many members of the community discovered the innovative use cases, although they employed the various techniques including the addition of the unique features to the function object and creating the custom decorators and docstring formats.
It’s crucial to realize that Python doesn’t bestow any semantics on the annotations. It only offers great syntactic support for tagging the metadata and a simple way to access it. Annotations are also entirely optional.
Let’s look at an example. Here is a function called func() that prints the sum of the three inputs – one, two, and three. Notably, func() does not return anything. One, the first argument, is left unannotated. The integer type is annotated for the third parameter, “three” whereas the string “annotating two” is annotated for the second input, “two.” The type float is indicated next to the return value. Take note of the “->” syntax (given below) when annotating the return value. The attached image demonstrates the overall sample code:
The function’s execution is in no way impacted by the annotations. Let’s use the int and string arguments respectively when using the func() twice. In both times, func() takes the appropriate action and ignores the annotations.
The attached image demonstrates the overall sample code:
Here is the outcome of applying both functions:
For your assistance, here is another example program. The create_user() function accepts the three values – name, age, and hobbies – and produces a dictionary or dict, as can be seen in the following image. The create users() function takes a list of tuples that define a list of users. This approach yields a list of dictionaries.
The dict-type variable u1 stores the results of the method call to the create user() method.
In addition, the List[dict] type variable users hold the results of the function call towards the create users() method. The attached image demonstrates the overall sample code:
All the users’ names, ages, and hobbies are displayed here:
Only the information about the variables are provided by the “__annotations__” attribute. We can employ the “__annotations__” attribute to retrieve the annotation information about the functions. You can understand this concept with the following given code. The attached image demonstrates the overall sample code:
All of the annotation information are included in the output dictionary. Keep in mind that the dictionary’s key for the return type is “return”. The keys to parameters are the parameter names.
Python is a powerful programming language with dynamic typing. It is supported by a vast array of libraries and functionalities and has a simple syntax similar to writing plain English. Annotations are one of these options. The purpose of annotations is to make the source code more readable and easier to understand. The function and variable annotations are the main two types of annotations used in Python. We covered both forms of Python annotations in this article with the aid of the relevant examples.