{"id":5042,"date":"2025-02-18T07:57:40","date_gmt":"2025-02-18T06:57:40","guid":{"rendered":"https:\/\/neogeo.fr\/python-evolutions-from-3-9-to-3-13-typing\/"},"modified":"2026-10-23T16:28:16","modified_gmt":"2026-10-23T14:28:16","slug":"python-evolutions-from-3-9-to-3-13-typing","status":"publish","type":"post","link":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/","title":{"rendered":"Python Evolutions from 3.9 to 3.13: Typing"},"content":{"rendered":"\n<p class=\"wp-block-paragraph\">While the <a href=\"https:\/\/www.python.org\/\">Python<\/a> standard library can be considered stable, the same cannot be said for the typing component, which is currently in a state of rapid development.<\/p>\n\n<p class=\"wp-block-paragraph\">As a reminder, typing in Python is optional, which is perfectly fine for small projects and scripts. However, as soon as a project grows in scale, typing function parameters helps maintain rigor and forces one to consider the correct data flows within the program. <\/p>\n\n<h2 class=\"wp-block-heading\">Version 3.9<\/h2>\n\n<p class=\"wp-block-paragraph\">In Python version 3.9, there is only one evolution in typing, but it significantly improves readability and simplifies typing-related code: built-in types <em><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">(list, dict&#8230;)<\/mark><\/em> can now be used to declare typing. \ud83c\udf89<\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">class Foo:\n    def add_items(self, items: list[str]) -&gt; None:\n\t\t\t    ...<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">I do not know about you, but for me, this reduces the entry barrier for typing so much that I would not mind integrating it even into small scripts.<\/p>\n\n<h2 class=\"wp-block-heading\">Version 3.10<\/h2>\n\n<p class=\"wp-block-paragraph\">Since Python version 3.10, the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-black-color\"><strong>| <\/strong><\/mark>operator can now be used to declare type unions (where a function accepts several different types, or to make them optional):<\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">class Foo:\n    def set_color(self, color: str|Color|None) -&gt; None:\n        ...\n\n    def get_color(self) -&gt; Color|None:\n\t\t\t    ...<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">A major effort was also made in this version to provide genericity in typing. For example, when defining a decorator, the type of the decorated function is not always known in advance. From now on, <em><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">ParamSpec <\/mark><\/em>can be used to indicate an unknown type.  <\/p>\n\n<p class=\"wp-block-paragraph\">Further clarity was also introduced with the addition of <em><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\">TypeAlias <\/mark><\/em>, which allows giving an explicit name to a complex type.<\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">StrCache: TypeAlias = &#039;Cache[str]&#039;<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">To create small functions that verify types (<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>is_bool, is_string<\/em><\/mark>, etc.), <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeGuards <\/em><\/mark>were introduced. <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeGuards <\/em><\/mark>are used for a rather complex practice called type narrowing. The latter is used for functions that accept input variables with several possible types. <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeGuard<\/em><\/mark> then allows for type checking to be implemented on the function&#8217;s input variables.   <\/p>\n\n<p class=\"wp-block-paragraph\">\ud83d\udd0eThe use of <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeGuards <\/em><\/mark>is not very simple, so I invite you to look at the Python <a href=\"https:\/\/docs.python.org\/3.10\/whatsnew\/3.10.html#pep-647-user-defined-type-guards\">documentation<\/a> in more detail if you are interested. <\/p>\n\n<h2 class=\"wp-block-heading\">Version 3.11<\/h2>\n\n<p class=\"wp-block-paragraph\">Continuing with complex additions, version 3.11 introduced <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Generic <\/em><\/mark><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-black-color\"><em><strong>Variadics<\/strong><\/em> <\/mark>to handle sets of elements with fixed sizes (a tensor with a fixed size, for example).<\/p>\n\n<p class=\"wp-block-paragraph\">A <em><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-black-color\"><strong>generic<\/strong> <\/mark><\/em>allows preserving a type between the input and output of a function. For example, if we take a function that copies a variable, it takes a variable as input which can be of any type, so we would type it as <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Any<\/em><\/mark>. Since the function returns a copy of the input variable, the return type of the function will be the same as that of the input variable (<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Any<\/em><\/mark>).  <\/p>\n\n<p class=\"wp-block-paragraph\">The problem is that with <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Any<\/em><\/mark>, there is no way to verify that the input and output types are the same, and this is where the <em><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-black-color\"><strong>generic<\/strong> <\/mark><\/em>comes into play.<\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">def copy_of_1(value: Any) -&gt; Any: # Le Any d&#039;entr\u00e9e et \n                                  # le Any de sortie \n                                  # ne sont pas forc\u00e9s \n                                  # d&#039;\u00eatre du m\u00eame type\n    return deepcopy(value)\n\n\nT = TypeVar(&quot;T&quot;)\n\ndef copy_of_2(value: T) -&gt; T:     # Les variables en entr\u00e9e \n                                  # et en sortie sont forc\u00e9es \n                                  # d&#039;\u00eatre du m\u00eame type\n    return deepcopy(value)<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Generic <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Variadics<\/em><\/mark>, on the other hand, are more complex and allow for handling multi-dimensional types. \ud83d\udd0eHere again, the implementation is subtle; I invite you to read the official <a href=\"https:\/\/docs.python.org\/3.11\/whatsnew\/3.11.html#whatsnew311-pep646\">documentation<\/a>.  <\/p>\n\n<p class=\"wp-block-paragraph\">However, among the small additions that can be useful to everyone, there are the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Required <\/em><\/mark>and <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>NotRequired <\/em><\/mark>types in <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypedDict<\/em><\/mark>:<\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">class Shape(TypedDict):\n    x: Required[int]\n    y: Required[int]\n    color: NotRequired[int]<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">The <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Self<\/em> <\/mark>type was also added, which is very practical for creating a constructor:<\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">class Shape:\n    @classmethod\n    def new(cls, x: int, y: int) -&gt; Self:\n        ...<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">A <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>type was also added. It can be used to indicate that a function parameter can be any type of literal string (a string hard-coded in the source, such as &#8220;Hello World!&#8221;). <\/p>\n\n<p class=\"wp-block-paragraph\">This type is primarily useful for enhancing security \ud83d\udcaa because it indicates that a variable must be hard-coded. Unlike a simple <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>str<\/em><\/mark>, this type ensures that the value comes directly from the source code without dynamic transformation. Thus, <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>establishes an important distinction between strings explicitly defined in the code and those obtained dynamically.  <\/p>\n\n<p class=\"wp-block-paragraph\">\ud83e\uddd0 If you are the type who likes to dig deeper (or if you are simply stubborn like me), here is what I understood about how <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>works:<\/p>\n\n<p class=\"wp-block-paragraph\">The <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>allows you to add a bit of security and rigor to your code without having overly drastic typing. To better visualize this, we can take a <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-black-color\">log<\/mark><\/strong> display function as an example. <\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">def log(level: str, message: str):\n    if level == &quot;Error&quot;:\n        print(message)\n\nlevel = &quot;Error&quot; + &quot;\\u200b&quot;  # &quot;Error&quot; avec un caract\u00e8re invisible (Zero Width Space)\nlog(level, &quot;Ce message s&#039;affiche !&quot;)<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">With this version of the function, we can see there is a security issue because our message will be displayed even if the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>level <\/em><\/mark>variable is not exactly equal to <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Error<\/em><\/mark>. Not a big deal, you might say. And indeed, it is not very important for a <strong>log<\/strong> function, but if it were about managing your databases&#8230;  <\/p>\n\n<p class=\"wp-block-paragraph\">Conversely, we have <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Literal<\/em><\/mark> at the extreme end of typing:<\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">from typing import Literal\n\nERROR: Literal[&quot;Error&quot;] = &quot;Error&quot;\n\ndef log(level: Literal[&quot;Error&quot;], message: str):\n    if level == ERROR:\n        print(message)\n\nlog(ERROR, &quot;Ce message s&#039;affiche !&quot;) # Pas d&#039;alert sur le type\n\nlevel = &quot;Error&quot; + &quot;\\u200b&quot;  # &quot;Erreur&quot; avec un caract\u00e8re invisible (Zero Width Space)\nlog(level, &quot;Ce message ne s&#039;affichera pas !&quot;) # Une erreur de type sera indiqu\u00e9e<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">With this version of the function, we strictly control the type of the input <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>level <\/em><\/mark>variable. However, as soon as the number of possible input types increases, the syntax becomes laborious. Similarly, it may not be possible to know all possible input types in advance (in the case of external components).  <\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">from typing import Literal\n\nINFO: Literal[&quot;Info&quot;] = &quot;Info&quot;\nWARNING: Literal[&quot;Warning&quot;] = &quot;Warning&quot;\nERROR: Literal[&quot;Error&quot;] = &quot;Error&quot;\n\ndef log(external_component: ???, # Le type n&#039;est pas connu\n        level: Literal[&quot;Info&quot;, &quot;Warning&quot;, &quot;Error&quot;, ...], # On pourrait avoir beaucoup de types possibles\n        message: str):\n    if level == ERROR:\n        print(message)<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">To remedy these two situations, the compromise of <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>was found:<\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">from typing import LiteralString, Literal\n\nINFO: Literal[&quot;Info&quot;] = &quot;Info&quot;\nWARNING: Literal[&quot;Warning&quot;] = &quot;Warning&quot;\nERROR: Literal[&quot;Error&quot;] = &quot;Error&quot;\n\ndef log(external_component: LiteralString, level: LiteralString, message: str):\n    if level == ERROR:\n        print(message)\n\nlog(INFO, &quot;Ce message ne s&#039;affichera pas !&quot;) # Pas d&#039;alert sur le type\nlog(WARNING, &quot;Ce message ne s&#039;affichera pas !&quot;) # Pas d&#039;alert sur le type\nlog(ERROR, &quot;Ce message s&#039;affiche !&quot;) # Pas d&#039;alert sur le type<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">It is also possible to use both <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Literal<\/em><\/mark> and <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>:<\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">from typing import LiteralString, Literal\n\nINFO: LiteralString = &quot;Info&quot; # On d\u00e9finit INFO avec un type moins pr\u00e9cis\nWARNING: Literal[&quot;Warning&quot;] = &quot;Warning&quot;\nERROR: Literal[&quot;Error&quot;] = &quot;Error&quot;\n\ndef log(external_component: LiteralString, \n        level: Literal[&quot;Warning&quot;, &quot;Error&quot;], # Level est soit du type Literal[&quot;Warning&quot;] soit du type Literal[&quot;Error&quot;]\n        message: str):\n    if level == ERROR:\n        print(message)\n\nlog(INFO, &quot;Ce message ne s&#039;affichera pas !&quot;) # Alerte sur le type\n\nlog(WARNING, &quot;Ce message ne s&#039;affichera pas !&quot;) # Pas d&#039;alerte sur le type\nlog(ERROR, &quot;Ce message s&#039;affiche !&quot;) # Pas d&#039;alerte sur le type\nlog(WARNING+ERROR, &quot;Ce message ne s&#039;affichera pas !&quot;) # Pas d&#039;alerte sur le type. Pas tr\u00e8s int\u00e9ressant mais pourquoi pas ...<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">From the two previous examples, we can conclude that <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark> groups all   <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Literal[&lt;&#8230;&gt;]  <\/em><\/mark><\/strong>where  <strong><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>&lt;&#8230;&gt;<\/em><\/mark><mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-black-color\"> <\/mark><\/strong>is a character string. Thus, we deduce that <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>is the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-black-color\"><strong>supertype<\/strong> <\/mark>of all literal string types. <\/p>\n\n<p class=\"wp-block-paragraph\">\ud83d\udea8Therefore, any &#8220;subtype&#8221; of <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>(<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Literal[&#8220;Error&#8221;] <\/em><\/mark>or even <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Literal[&#8220;Warning&#8221;]<\/em><\/mark>) is compatible with <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>, but not the other way around (refer to the <strong>INFO<\/strong> variable in the previous example). <\/p>\n\n<p class=\"wp-block-paragraph\">\ud83d\udea8Similarly, the <strong>supertype<\/strong> <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>is itself a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>str<\/em><\/mark>, making <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>str<\/em><\/mark> a <strong>super supertype<\/strong>. <\/p>\n\n<p class=\"wp-block-paragraph\">\ud83d\udea8Finally, using the same logic as before, we deduce that a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>str<\/em><\/mark> is not compatible with a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>. By this, we mean that it is possible to assign a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>to a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>str<\/em><\/mark>, but not vice versa.  <\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">literal_string: LiteralString\ns: str = literal_string                 # OK\n\nliteral_string: LiteralString = s       # Erreur : \n                                        # On attendait un\n                                        # LiteralString, \n                                        # on a un str\nliteral_string: LiteralString = &quot;hello&quot; # OK<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">A string created by composing <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>typed objects is, for its part, acceptable as a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString <\/em><\/mark>(as with <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Literal<\/em><\/mark>).<\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">literal_string_1: LiteralString = &quot;Hello&quot;\nliteral_string_2: LiteralString = &quot; World&quot;\n\ncomposed_string: LiteralString = literal_string_1 + literal_string_2 + &quot; !&quot;  # Toujours un LiteralString<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">This type is useful for sensitive APIs where arbitrary user-generated strings could cause issues. <\/p>\n\n<p class=\"wp-block-paragraph\">\ud83d\udd0eFor more examples, you can refer to the official Python <a href=\"https:\/\/docs.python.org\/3.11\/whatsnew\/3.11.html#pep-675-arbitrary-literal-string-type\">documentation<\/a>.<\/p>\n\n<p class=\"wp-block-paragraph\">Regarding decorators, version 3.11 adds <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>dataclass_transform<\/em><\/mark>, which is applicable to a class, a metaclass, or a decorator. This decorator allows marking an object as providing <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>dataclass <\/em><\/mark>-like behavior while performing type checking. <\/p>\n\n<p class=\"wp-block-paragraph\">As a reminder, the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>dataclass<\/em><\/mark> decorator adds generated and special methods to a class. For example, we will have methods like <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>__init__<\/em><\/mark>, <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>__repr__ <\/em><\/mark>or <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>__eq__<\/em><\/mark>. <\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\"># Le d\u00e9corateur create_model est d\u00e9fini par une biblioth\u00e8que.\n@typing.dataclass_transform()\ndef create_model(cls: Type[T]) -&gt; Type[T]:\n    cls.__init__ = ...\n    cls.__eq__ = ...\n    cls.__ne__ = ...\n    return cls\n\n# Le d\u00e9corateur create_model peut d\u00e9sormais \u00eatre utilis\u00e9 \n# pour cr\u00e9er de nouvelles classes de mod\u00e8les :\n@create_model\nclass CustomerModel:\n    id: int\n    name: str\n\nc = CustomerModel(id=327, name=&quot;Eric Idle&quot;)<\/code><\/pre>\n\n<h2 class=\"wp-block-heading\">Version 3.12<\/h2>\n\n<p class=\"wp-block-paragraph\">Version 3.12, for its part, introduces the use of the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypedDict <\/em><\/mark>dictionary type to achieve more precise typing of arguments (<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>**kwargs<\/em><\/mark>).<\/p>\n\n<p class=\"wp-block-paragraph\">Before this addition, <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>**kwargs<\/em><\/mark> could be typed provided that all the keyword arguments they specified were of the same type. However, this behavior was very limiting. For example, annotating <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>**kwargs<\/em><\/mark> with a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>str<\/em><\/mark> type means that the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>**kwargs<\/em><\/mark> type is actually a <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em> dict[str, str]<\/em><\/mark> and therefore all keyword arguments in <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>foo<\/em> <\/mark>are strings.  <\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">def foo(**kwargs: str) -&gt; None: ...<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Unfortunately, it often happens that keyword arguments passed via <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>**kwargs<\/em><\/mark> have different types depending on the keyword name. In such cases, it was not possible to annotate the type of the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>**kwargs<\/em><\/mark>. <\/p>\n\n<p class=\"wp-block-paragraph\">Now, by using <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypedDict<\/em><\/mark> to type <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>**kwargs<\/em><\/mark>, it is possible to assign a dictionary as the type for <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>**kwargs<\/em><\/mark>. Thus, <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>**kwargs<\/em><\/mark> can be typed separately (by dictionary key). <\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">from typing import TypedDict, Unpack\n\nclass Movie(TypedDict):\n  name: str\n  year: int\n\ndef foo(**kwargs: Unpack[Movie]): ...<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">\ud83d\udd0eFor more details, I invite you to consult the official Python <a href=\"https:\/\/docs.python.org\/3.12\/whatsnew\/3.12.html#whatsnew312-pep692\">documentation<\/a>. <\/p>\n\n<p class=\"wp-block-paragraph\">Version 3.12 also offers a new <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>override <\/em><\/mark>decorator that will undoubtedly be useful for a large majority. The latter indicates that a method in a subclass is intended to override a method (or an attribute) in a parent class. <\/p>\n\n<p class=\"wp-block-paragraph\">\u2728This version also brings new syntactic features to create generic classes and functions in an explicit and compact way. <\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">def max[T](args: Iterable[T]) -&gt; T:\n    ...\n\nclass list[T]:\n    def __getitem__(self, index: int, \/) -&gt; T:\n        ...\n\n    def append(self, element: T) -&gt; None:\n        ...<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Additionally, a new way to declare type aliases is introduced. As shown in the following example, the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>type <\/em><\/mark>statement is used, which creates an instance of <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeAliasType <\/em><\/mark>and makes the declaration explicit. <\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">type Point = tuple[float, float]<\/code><\/pre>\n\n<h2 class=\"wp-block-heading\">Version 3.13<\/h2>\n\n<p class=\"wp-block-paragraph\">With version 3.13, it is now possible to define a default value for type parameters (<mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeVar, ParamSpec<\/em><\/mark>, and <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em> TypeVarTuple<\/em><\/mark>).<\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">T = TypeVar(&quot;T&quot;, default=int) # Si aucun type n&#039;est sp\u00e9cifi\u00e9, \n                              # T sera de type int\n\n@dataclass\nclass Box(Generic[T]):\n    value: T | None = None\n\nreveal_type(Box())                      # Le type est Box[int]\nreveal_type(Box(value=&quot;Hello World!&quot;))  # Le type est Box[str]<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">It is also possible, since this version, to mark a class or a function as deprecated using the new <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>deprecated<\/em><\/mark> decorator. Thus, developers can be informed when they use these classes and functions so they can implement the necessary migrations. <\/p>\n\n<p class=\"wp-block-paragraph\">Another very useful small addition is the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>ReadOnly <\/em><\/mark>qualifier for the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypedDict <\/em><\/mark>type, which allows defining certain keys as read-only. The correct use of these read-only keys is intended to be enforced only by static type checkers and not by Python itself at runtime. <\/p>\n\n<p class=\"wp-block-paragraph\">Finally, version 3.13 revisits its addition of <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeGuard <\/em><\/mark>from version 3.10. This version offers a more intuitive alternative to <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeGuard: TypeIs<\/em><\/mark>. This new form allows for the annotation of functions that can be used to refine the type of a value.  <\/p>\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"\" data-line=\"\">from typing import assert_type, final, TypeIs\n\nclass Parent: pass\nclass Child(Parent): pass\n@final\nclass Unrelated: pass\n\ndef is_parent(val: object) -&gt; TypeIs[Parent]:\n    return isinstance(val, Parent)\n\ndef run(arg: Child | Unrelated):\n    if is_parent(arg):\n        # Le type de ``arg`` est r\u00e9duit \u00e0 l&#039;intersection entre \n        # ``Parent`` et ``Child``, \n        # ce qui \u00e9quivaut \u00e0 ``Child``.\n        assert_type(arg, Child)\n    else:\n        # Le type de ``arg`` est r\u00e9duit pour exclure ``Parent``, \n        # de sorte qu&#039;il ne reste que ``Unrelated``.\n        assert_type(arg, Unrelated)<\/code><\/pre>\n\n<p class=\"wp-block-paragraph\">Unlike the existing <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeGuard <\/em><\/mark>special form, <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeIs<\/em><\/mark> can refine the type in both the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>if <\/em><\/mark>and <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>else <\/em><\/mark>branches of a condition. However, <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeIs<\/em><\/mark> cannot be used when the input and output types are incompatible (for example, <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>list[object] to list[int]<\/em><\/mark>), or when the function does not return <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>True <\/em><\/mark>for all instances of the narrowed type.  <\/p>\n\n<p class=\"wp-block-paragraph\">\ud83d\udd0eFor more details, I refer you to the official <a href=\"https:\/\/docs.python.org\/3.13\/library\/typing.html#typing.TypeIs\">documentation<\/a>. <\/p>\n\n<h2 class=\"wp-block-heading\">Conclusion<\/h2>\n\n<p class=\"wp-block-paragraph\">\ud83d\udcc8We can see that typing in Python is in full evolution, with each version bringing its share of improvements to make it more expressive, more robust, and easier to use. <\/p>\n\n<p class=\"wp-block-paragraph\">Recent additions, such as <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>Self, LiteralString, TypedDict<\/em><\/mark> or <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>override<\/em><\/mark>, show a desire to make typing more intuitive and useful in concrete scenarios.<\/p>\n\n<p class=\"wp-block-paragraph\">With version 3.13, Python continues on this path by offering more flexible tools and readjusting certain decisions, such as the <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeIs<\/em><\/mark> alternative for <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeGuard<\/em><\/mark>.<\/p>\n\n<p class=\"wp-block-paragraph\">\ud83d\udc49In summary, typing in Python presents advantages (and also, sometimes, disadvantages) that deserve to be taken into account in your developments.<\/p>\n\n<p class=\"wp-block-paragraph\">\u2795 On one hand, it brings better security by reducing the risk of bugs and attacks. By imposing clear types, it also allows for better code readability, especially when structures and workflows become more complex. This facilitates not only maintenance but also the handover of code to other developers, thus making collaboration smoother.  <\/p>\n\n<p class=\"wp-block-paragraph\">\u2796 However, typing in Python also has some limitations. Certain types or features, such as <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>TypeGuard<\/em><\/mark>, can be difficult to master. Furthermore, some types, such as <mark style=\"background-color:rgba(0, 0, 0, 0)\" class=\"has-inline-color has-vivid-cyan-blue-color\"><em>LiteralString<\/em><\/mark>, do not always bring real added value considering their complexity of use. Finally, the addition of types can sometimes visually clutter the code, which can hinder its readability.   <\/p>\n\n<p class=\"wp-block-paragraph\">For my part, I believe it is essential to pay attention to typing. It contributes greatly to the understanding and maintenance of code, especially when it comes to taking over someone else&#8217;s work. In my view, it is at the very least necessary to type method prototypes, clearly specifying the types of inputs and outputs. Ultimately, the most important thing remains to discuss typing standards with your team in order to adopt a consistent approach adapted to the project&#8217;s needs.   <\/p>\n\n<p class=\"wp-block-paragraph\">Regardless, the Python language is gaining maturity, but typing remains a field of innovation. We look forward to discovering its future evolutions! <\/p>\n\n<p class=\"wp-block-paragraph\"><em>P.S.: To learn more about Python&#8217;s evolutions (excluding typing), I invite you to consult our article entitled &#8220;Discover the major evolutions of Python from 3.9 to 3.13&#8221;.<\/em><\/p>\n\n<hr class=\"wp-block-separator has-alpha-channel-opacity\"\/>\n\n<p class=\"wp-block-paragraph\"><em>Author: Mathilde Pommier<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>While the Python standard library can be considered stable, the same cannot be said for the typing component, which is currently in a state of rapid development. As a reminder, typing in Python is optional, which is perfectly fine for small projects and scripts. However, as soon as a project grows in scale, typing function &#8230; <a title=\"Python Evolutions from 3.9 to 3.13: Typing\" class=\"read-more\" href=\"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/\" aria-label=\"Read more about Python Evolutions from 3.9 to 3.13: Typing\">Read more<\/a><\/p>\n","protected":false},"author":5,"featured_media":5043,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[60],"tags":[],"class_list":["post-5042","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-uncategorized-en"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.7 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Python Typing: What Changes from 3.9 to 3.13 | NEOGEO<\/title>\n<meta name=\"description\" content=\"TypeIs, LiteralString, override, TypedDict for kwargs: the evolutions of Python typing version by version, from 3.9 to 3.13.\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Python Typing: What Changes from 3.9 to 3.13 | NEOGEO\" \/>\n<meta property=\"og:description\" content=\"TypeIs, LiteralString, override, TypedDict for kwargs: the evolutions of Python typing version by version, from 3.9 to 3.13.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/\" \/>\n<meta property=\"og:site_name\" content=\"NEOGEO\" \/>\n<meta property=\"article:published_time\" content=\"2025-02-18T06:57:40+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2026-10-23T14:28:16+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/neogeo.fr\/wp-content\/uploads\/2025\/02\/close-up-pattern-scales-1-scaled-1.webp\" \/>\n\t<meta property=\"og:image:width\" content=\"2560\" \/>\n\t<meta property=\"og:image:height\" content=\"1435\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/webp\" \/>\n<meta name=\"author\" content=\"Philippe DESTR\u00c9\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Philippe DESTR\u00c9\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"11 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/\"},\"author\":{\"name\":\"Philippe DESTR\u00c9\",\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/#\\\/schema\\\/person\\\/69685e84302b110f77d59dc8ee6e2d40\"},\"headline\":\"Python Evolutions from 3.9 to 3.13: Typing\",\"datePublished\":\"2025-02-18T06:57:40+00:00\",\"dateModified\":\"2026-10-23T14:28:16+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/\"},\"wordCount\":1778,\"commentCount\":0,\"publisher\":{\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/neogeo.fr\\\/wp-content\\\/uploads\\\/2025\\\/02\\\/close-up-pattern-scales-1-scaled-1.webp\",\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/\",\"url\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/\",\"name\":\"Python Typing: What Changes from 3.9 to 3.13 | NEOGEO\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/neogeo.fr\\\/wp-content\\\/uploads\\\/2025\\\/02\\\/close-up-pattern-scales-1-scaled-1.webp\",\"datePublished\":\"2025-02-18T06:57:40+00:00\",\"dateModified\":\"2026-10-23T14:28:16+00:00\",\"description\":\"TypeIs, LiteralString, override, TypedDict for kwargs: the evolutions of Python typing version by version, from 3.9 to 3.13.\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/#primaryimage\",\"url\":\"https:\\\/\\\/neogeo.fr\\\/wp-content\\\/uploads\\\/2025\\\/02\\\/close-up-pattern-scales-1-scaled-1.webp\",\"contentUrl\":\"https:\\\/\\\/neogeo.fr\\\/wp-content\\\/uploads\\\/2025\\\/02\\\/close-up-pattern-scales-1-scaled-1.webp\",\"width\":2560,\"height\":1435,\"caption\":\"snake skin bright blue --ar 16:9 Job ID: 4d0ffe6a-e315-47c0-87b2-59b605c9495c\"},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/python-evolutions-from-3-9-to-3-13-typing\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Accueil\",\"item\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Python Evolutions from 3.9 to 3.13: Typing\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/#website\",\"url\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/\",\"name\":\"NEOGEO\",\"description\":\"Optimisez,\u00a0valorisez,\\u2028partagez\u00a0vos\u00a0donn\u00e9es\u00a0spatiales\",\"publisher\":{\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/#organization\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/#organization\",\"name\":\"NEOGEO\",\"url\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/neogeo.fr\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/NEOGEO-LOGO.svg\",\"contentUrl\":\"https:\\\/\\\/neogeo.fr\\\/wp-content\\\/uploads\\\/2026\\\/06\\\/NEOGEO-LOGO.svg\",\"width\":145,\"height\":42,\"caption\":\"NEOGEO\"},\"image\":{\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/#\\\/schema\\\/logo\\\/image\\\/\"}},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/#\\\/schema\\\/person\\\/69685e84302b110f77d59dc8ee6e2d40\",\"name\":\"Philippe DESTR\u00c9\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b366889cd846213d38b977f63dd60b6af7e9ed5b067a024a76fe0865155ef9db?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b366889cd846213d38b977f63dd60b6af7e9ed5b067a024a76fe0865155ef9db?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b366889cd846213d38b977f63dd60b6af7e9ed5b067a024a76fe0865155ef9db?s=96&d=mm&r=g\",\"caption\":\"Philippe DESTR\u00c9\"},\"url\":\"https:\\\/\\\/neogeo.fr\\\/en\\\/author\\\/pdestreneogeo\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Python Typing: What Changes from 3.9 to 3.13 | NEOGEO","description":"TypeIs, LiteralString, override, TypedDict for kwargs: the evolutions of Python typing version by version, from 3.9 to 3.13.","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/","og_locale":"en_US","og_type":"article","og_title":"Python Typing: What Changes from 3.9 to 3.13 | NEOGEO","og_description":"TypeIs, LiteralString, override, TypedDict for kwargs: the evolutions of Python typing version by version, from 3.9 to 3.13.","og_url":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/","og_site_name":"NEOGEO","article_published_time":"2025-02-18T06:57:40+00:00","article_modified_time":"2026-10-23T14:28:16+00:00","og_image":[{"width":2560,"height":1435,"url":"https:\/\/neogeo.fr\/wp-content\/uploads\/2025\/02\/close-up-pattern-scales-1-scaled-1.webp","type":"image\/webp"}],"author":"Philippe DESTR\u00c9","twitter_card":"summary_large_image","twitter_misc":{"Written by":"Philippe DESTR\u00c9","Est. reading time":"11 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/#article","isPartOf":{"@id":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/"},"author":{"name":"Philippe DESTR\u00c9","@id":"https:\/\/neogeo.fr\/en\/#\/schema\/person\/69685e84302b110f77d59dc8ee6e2d40"},"headline":"Python Evolutions from 3.9 to 3.13: Typing","datePublished":"2025-02-18T06:57:40+00:00","dateModified":"2026-10-23T14:28:16+00:00","mainEntityOfPage":{"@id":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/"},"wordCount":1778,"commentCount":0,"publisher":{"@id":"https:\/\/neogeo.fr\/en\/#organization"},"image":{"@id":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/#primaryimage"},"thumbnailUrl":"https:\/\/neogeo.fr\/wp-content\/uploads\/2025\/02\/close-up-pattern-scales-1-scaled-1.webp","inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/#respond"]}]},{"@type":"WebPage","@id":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/","url":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/","name":"Python Typing: What Changes from 3.9 to 3.13 | NEOGEO","isPartOf":{"@id":"https:\/\/neogeo.fr\/en\/#website"},"primaryImageOfPage":{"@id":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/#primaryimage"},"image":{"@id":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/#primaryimage"},"thumbnailUrl":"https:\/\/neogeo.fr\/wp-content\/uploads\/2025\/02\/close-up-pattern-scales-1-scaled-1.webp","datePublished":"2025-02-18T06:57:40+00:00","dateModified":"2026-10-23T14:28:16+00:00","description":"TypeIs, LiteralString, override, TypedDict for kwargs: the evolutions of Python typing version by version, from 3.9 to 3.13.","breadcrumb":{"@id":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/#primaryimage","url":"https:\/\/neogeo.fr\/wp-content\/uploads\/2025\/02\/close-up-pattern-scales-1-scaled-1.webp","contentUrl":"https:\/\/neogeo.fr\/wp-content\/uploads\/2025\/02\/close-up-pattern-scales-1-scaled-1.webp","width":2560,"height":1435,"caption":"snake skin bright blue --ar 16:9 Job ID: 4d0ffe6a-e315-47c0-87b2-59b605c9495c"},{"@type":"BreadcrumbList","@id":"https:\/\/neogeo.fr\/en\/python-evolutions-from-3-9-to-3-13-typing\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Accueil","item":"https:\/\/neogeo.fr\/en\/"},{"@type":"ListItem","position":2,"name":"Python Evolutions from 3.9 to 3.13: Typing"}]},{"@type":"WebSite","@id":"https:\/\/neogeo.fr\/en\/#website","url":"https:\/\/neogeo.fr\/en\/","name":"NEOGEO","description":"Optimisez,\u00a0valorisez,\u2028partagez\u00a0vos\u00a0donn\u00e9es\u00a0spatiales","publisher":{"@id":"https:\/\/neogeo.fr\/en\/#organization"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/neogeo.fr\/en\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/neogeo.fr\/en\/#organization","name":"NEOGEO","url":"https:\/\/neogeo.fr\/en\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/neogeo.fr\/en\/#\/schema\/logo\/image\/","url":"https:\/\/neogeo.fr\/wp-content\/uploads\/2026\/06\/NEOGEO-LOGO.svg","contentUrl":"https:\/\/neogeo.fr\/wp-content\/uploads\/2026\/06\/NEOGEO-LOGO.svg","width":145,"height":42,"caption":"NEOGEO"},"image":{"@id":"https:\/\/neogeo.fr\/en\/#\/schema\/logo\/image\/"}},{"@type":"Person","@id":"https:\/\/neogeo.fr\/en\/#\/schema\/person\/69685e84302b110f77d59dc8ee6e2d40","name":"Philippe DESTR\u00c9","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/b366889cd846213d38b977f63dd60b6af7e9ed5b067a024a76fe0865155ef9db?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/b366889cd846213d38b977f63dd60b6af7e9ed5b067a024a76fe0865155ef9db?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b366889cd846213d38b977f63dd60b6af7e9ed5b067a024a76fe0865155ef9db?s=96&d=mm&r=g","caption":"Philippe DESTR\u00c9"},"url":"https:\/\/neogeo.fr\/en\/author\/pdestreneogeo\/"}]}},"_links":{"self":[{"href":"https:\/\/neogeo.fr\/en\/wp-json\/wp\/v2\/posts\/5042","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/neogeo.fr\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/neogeo.fr\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/neogeo.fr\/en\/wp-json\/wp\/v2\/users\/5"}],"replies":[{"embeddable":true,"href":"https:\/\/neogeo.fr\/en\/wp-json\/wp\/v2\/comments?post=5042"}],"version-history":[{"count":1,"href":"https:\/\/neogeo.fr\/en\/wp-json\/wp\/v2\/posts\/5042\/revisions"}],"predecessor-version":[{"id":5044,"href":"https:\/\/neogeo.fr\/en\/wp-json\/wp\/v2\/posts\/5042\/revisions\/5044"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/neogeo.fr\/en\/wp-json\/wp\/v2\/media\/5043"}],"wp:attachment":[{"href":"https:\/\/neogeo.fr\/en\/wp-json\/wp\/v2\/media?parent=5042"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/neogeo.fr\/en\/wp-json\/wp\/v2\/categories?post=5042"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/neogeo.fr\/en\/wp-json\/wp\/v2\/tags?post=5042"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}