Here are resources for more information about annotations and PEP 593:
Annotated Type Hints
The original proposed use was to provide extra information about a parameter—for example, the units for a variable. In the code below, the annotation of
"seconds", and the return annotation of
"miles per hour" tells the developer what units should be used with the values passed into this function.
00:32 PEP 484 introduced the use of annotations for type hints. This goes beyond the case of what’s being shown here of units, and indicating the type of the variable being used. Type hints have become the most common use of annotations. Because of this, and because a lot of tools are now using it, the previous use has kind of been eclipsed.
Running this, I get the return value of 3.4 miles per hour, and I can look at the
.__annotations__ dictionary associated with the function, which shows the attributes that are in the function and the annotations for each.
The execution here is no different, but the annotations are. It shows that the attributes are associated with
float types. The new
Annotated class in Python 3.9 lets you do both of these things.
In this case, on line 6, I’m creating an annotation which is a combination of
float and the units
"feet". On line 7, I do this again for
"miles per hour". In the function declaration on line 9, I can use these annotations—
"miles per hours" as the return—or I can just put the class directly inside of it, like I have with
Calling it with the
include_extras parameter set to
True, you get the
Annotated classes inside of it as well. This means you—as the programmer—no longer have to make the decision between whether you’re annotating for types or annotating for units. You can do both.
03:41 If you’re finding that you’re doing a lot of type hints with units, a useful utility class would be an annotation factory, like the one shown here. This factory allows you to create annotation classes that are bound to a type, and then when you use them, you specify the units.
The annotation classes are accessed using square brackets, like dictionaries. The square bracket syntax triggers
.__getitem__() inside of a class, so this function is what will be called when the class is called with the square brackets.
There are two possible ways of calling the instance: one with a tuple and one without a tuple. Because
Annotated takes a tuple, the first thing you do in line 9 and 10 is check if what’s passed in is a tuple. If it is, you join the existing
.type_hint with the tuple that’s being passed in, and use that as the key to the
Annotated class. If it isn’t, then you just directly use the annotation and the type key. Lines 14 and 15 represent the class using the
.__class__.__name__, and the
.type_hint that is constructed.
On line 19, you can see the instantiation of the factory using a float. On line 21, that float is used for distance, time, and the return, passing in the units of
"miles per hour".
Become a Member to join the conversation.