<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Runtime on Shane&apos;s Personal Blog</title><description>Recent content in Runtime on Shane&apos;s Personal Blog</description><link>https://shanechang.com/tags/runtime/</link><language>en-us</language><lastBuildDate>Tue, 16 Sep 2025 00:00:00 GMT</lastBuildDate><atom:link href="https://shanechang.com/tags/runtime/index.xml" rel="self" type="application/rss+xml"/><item><title>Python&apos;s Runtime Identity Crisis: A Guide to Knowing What Type You&apos;re Holding</title><link>https://shanechang.com/p/python-runtime-type-introspection-guide/</link><guid isPermaLink="true">https://shanechang.com/p/python-runtime-type-introspection-guide/</guid><description>&lt;img src=&quot;https://shanechang.com/_astro/cover.ojhu4dpo_ZfmLHM.webp&quot; alt=&quot;Featured image of post Python&apos;s Runtime Identity Crisis: A Guide to Knowing What Type You&apos;re Holding&quot; /&gt;&lt;h2 id=&quot;the-lie-we-tell-ourselves&quot;&gt;The Lie We Tell Ourselves&lt;/h2&gt;
&lt;p&gt;I used to think my code was safe. &lt;code&gt;mypy&lt;/code&gt; was happy. My IDE flashed a reassuring green checkmark. My Pydantic models were beautifully annotated. “Of course, this &lt;code&gt;Message[int]&lt;/code&gt; knows it’s holding an integer,” I’d tell myself. “The types are &lt;em&gt;right there&lt;/em&gt;.”&lt;/p&gt;
&lt;p&gt;Then I tried to ask my model, at runtime, what type it was holding. The response was a confused shrug.&lt;/p&gt;
&lt;p&gt;It turns out there are two worlds: the pristine, orderly world of static type checking, and the chaotic, messy reality of runtime. The map your type checker uses is often thrown away before your code actually runs. This is the story of how to draw a new map—a reliable way to ask your code, “What type are you, &lt;em&gt;really&lt;/em&gt;?”&lt;/p&gt;
&lt;h2 id=&quot;the-two-worlds-static-blueprints-vs-runtime-reality&quot;&gt;The Two Worlds: Static Blueprints vs. Runtime Reality&lt;/h2&gt;
&lt;p&gt;Think of type hints like an architect’s blueprint for a house. The blueprint for &lt;code&gt;list[int]&lt;/code&gt; clearly says, “This is a list, and it must contain integers.” &lt;code&gt;mypy&lt;/code&gt; and your IDE are like building inspectors who check the blueprint for errors. They’ll tell you if you try to put a &lt;code&gt;str&lt;/code&gt; where an &lt;code&gt;int&lt;/code&gt; should go.&lt;/p&gt;
&lt;p&gt;But when Python &lt;em&gt;runs&lt;/em&gt; the code, it’s not looking at the blueprint anymore. It’s standing inside the finished house. All it sees is a list. The &lt;code&gt;[int]&lt;/code&gt; part? That’s just a faint memory, a notation on a blueprint that got filed away.&lt;/p&gt;
&lt;p&gt;This is the heart of the problem. We, as developers, need to be able to look at the finished house and figure out what was on the blueprint. We need to do some runtime detective work.&lt;/p&gt;
&lt;h2 id=&quot;level-1-the-simplest-clue---just-ask-the-value&quot;&gt;Level 1: The Simplest Clue - Just Ask the Value&lt;/h2&gt;
&lt;p&gt;Our first tool is the most direct. If you want to know what something is, just ask it. In Python, that’s the &lt;code&gt;type()&lt;/code&gt; function.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-default github-dark-default&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#0d1117;color:#1f2328;--shiki-dark:#e6edf3; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# Trivial Example: What is 5?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;5&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# Output: &amp;#x3C;class &apos;int&apos;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# Realistic Example: Inside a Pydantic model&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; pydantic &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; BaseModel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt; User&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;BaseModel&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;    name: &lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;str&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;    age: &lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;int&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;user &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; User(&lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt;name&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;Alice&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt;age&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;30&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# What&apos;s the type of the &apos;age&apos; we received?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(user.age))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# Output: &amp;#x3C;class &apos;int&apos;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This is our bedrock, our source of ground truth. When you have a value, &lt;code&gt;type(value)&lt;/code&gt; will never lie to you. It tells you what you have &lt;em&gt;right now&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;But what if you don’t have a value yet? What if you’re writing a function that needs to know what type of list it’s &lt;em&gt;supposed&lt;/em&gt; to receive, even if the list is empty? For that, we need to dig deeper.&lt;/p&gt;
&lt;h2 id=&quot;level-2-reading-the-blueprints-margins-with-typing&quot;&gt;Level 2: Reading the Blueprint’s Margins with &lt;code&gt;typing&lt;/code&gt;&lt;/h2&gt;
&lt;p&gt;Sometimes, Python doesn’t throw the &lt;em&gt;whole&lt;/em&gt; blueprint away. For special objects from the &lt;code&gt;typing&lt;/code&gt; module, it keeps some notes in the margins. We can read these notes with two helper functions: &lt;code&gt;get_origin&lt;/code&gt; and &lt;code&gt;get_args&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;get_origin(some_type)&lt;/code&gt; is like asking, “What’s the main container type?” (e.g., &lt;code&gt;list&lt;/code&gt;, &lt;code&gt;dict&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;&lt;code&gt;get_args(some_type)&lt;/code&gt; is like asking, “What are the specific types inside?” (e.g., &lt;code&gt;int&lt;/code&gt;, &lt;code&gt;str&lt;/code&gt;, &lt;code&gt;float&lt;/code&gt;).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Let’s see them in action:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-default github-dark-default&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#0d1117;color:#1f2328;--shiki-dark:#e6edf3; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; typing &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; get_origin, get_args, Optional, Dict&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# The blueprint for a list of integers&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;int_list_type &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; list[&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;Origin: &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;get_origin(int_list_type)&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)   &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# --&gt; &amp;#x3C;class &apos;list&apos;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;Args: &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;get_args(int_list_type)&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)     &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# --&gt; (&amp;#x3C;class &apos;int&apos;&gt;,)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# Works for more complex types, too&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;user_data_type &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; Dict[&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;, Optional[&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;]]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;Origin: &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;get_origin(user_data_type)&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)   &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# --&gt; &amp;#x3C;class &apos;dict&apos;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# The args are the key and value types&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;Args: &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;get_args(user_data_type)&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)     &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# --&gt; (&amp;#x3C;class &apos;str&apos;&gt;, typing.Optional[int])&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This feels powerful! It seems like we’ve solved it. But a new villain enters the scene, and this is where most developers get stuck.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Trap:&lt;/strong&gt; What happens if you use these on a normal class?&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-default github-dark-default&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#0d1117;color:#1f2328;--shiki-dark:#e6edf3; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt; Message&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;    ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(get_origin(Message)) &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# --&gt; None&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(get_args(Message))   &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# --&gt; ()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Nothing. These tools only work on the special constructs from the &lt;code&gt;typing&lt;/code&gt; module, not on regular classes. And as it turns out, a specialized Pydantic generic like &lt;code&gt;Message[int]&lt;/code&gt; behaves a lot more like a regular class than a typing construct.&lt;/p&gt;
&lt;h2 id=&quot;the-boss-level-pydantic-v2s-clever-disguise&quot;&gt;The Boss Level: Pydantic v2’s Clever Disguise&lt;/h2&gt;
&lt;p&gt;When you write &lt;code&gt;MyGenericModel[int]&lt;/code&gt;, Pydantic doesn’t just store &lt;code&gt;int&lt;/code&gt; somewhere. It dynamically creates a &lt;em&gt;brand new class&lt;/em&gt; on the fly. This new class is a subclass of &lt;code&gt;MyGenericModel&lt;/code&gt;, and it’s been specifically tailored to handle integers.&lt;/p&gt;
&lt;p&gt;This is incredibly powerful, but it means our &lt;code&gt;get_origin&lt;/code&gt;/&lt;code&gt;get_args&lt;/code&gt; trick won’t work. We’re dealing with a real class, not a typing annotation. I remember spending hours on this, thinking I was going crazy. “Why can’t I get the &lt;code&gt;int&lt;/code&gt; out of &lt;code&gt;Message[int]&lt;/code&gt;?!”&lt;/p&gt;
&lt;p&gt;The secret is that Pydantic leaves clues for us inside this new class. We just have to know where to look. There are two reliable spots:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;The Secret Metadata Pouch:&lt;/strong&gt; A hidden attribute called &lt;code&gt;__pydantic_generic_metadata__&lt;/code&gt;. This is the most direct and precise clue, telling us exactly what &lt;code&gt;T&lt;/code&gt; was specialized with.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Public Field Annotation:&lt;/strong&gt; Pydantic updates the &lt;code&gt;annotation&lt;/code&gt; on the model’s fields. So, on a &lt;code&gt;Message[int]&lt;/code&gt; class, the &lt;code&gt;content&lt;/code&gt; field’s annotation is no longer &lt;code&gt;T&lt;/code&gt;, but &lt;code&gt;int&lt;/code&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2 id=&quot;the-grand-unifying-strategy-a-three-layer-forensic-kit&quot;&gt;The Grand Unifying Strategy: A Three-Layer Forensic Kit&lt;/h2&gt;
&lt;p&gt;So, how do we combine all this knowledge into a single, reliable strategy? We build a function that checks for clues in the right order, from most specific to most general.&lt;/p&gt;
&lt;p&gt;First, we need a little helper to make our type names readable. Think of it as a magnifying glass that works on any kind of clue.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-default github-dark-default&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#0d1117;color:#1f2328;--shiki-dark:#e6edf3; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; typing &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; Any, get_origin, get_args&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#8250DF;--shiki-dark:#D2A8FF&quot;&gt; pretty_type_name&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(tp: Any) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;    &quot;&quot;&quot;A helper to get readable names for any type.&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;    # Is it a plain class like `int` or `User`?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt; hasattr&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(tp, &lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;__name__&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; tp.&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;__name__&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;    # Is it a typing construct like `list[int]`?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;    origin &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; get_origin(tp)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;    if&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; origin:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;        # Recursively pretty-print the inner types&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;        inner &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt; &quot;, &quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;.join(pretty_type_name(a) &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;for&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; a &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;in&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; get_args(tp))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;        base &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt; getattr&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(origin, &lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;__name__&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(origin))&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt; f&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;base&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;[&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;inner&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;]&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;    # If all else fails, just convert it to a string&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;    return&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt; str&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(tp)&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now, we can build our master detective method inside our generic Pydantic model. We’ll use a &lt;code&gt;@computed_field&lt;/code&gt; to make this information easily accessible.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-default github-dark-default&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#0d1117;color:#1f2328;--shiki-dark:#e6edf3; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; typing &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; Generic, TypeVar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; pydantic &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; BaseModel, computed_field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;T &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; TypeVar(&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;T&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt; Message&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;BaseModel&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;, Generic[T]):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;    content: T&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8250DF;--shiki-dark:#D2A8FF&quot;&gt;    @computed_field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8250DF;--shiki-dark:#D2A8FF&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;property&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#8250DF;--shiki-dark:#D2A8FF&quot;&gt; param_type&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(self) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;        &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;        The design-time type. What was this generic parameterized with?&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;        &quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;        # 1. Check Pydantic&apos;s secret metadata pouch first. It&apos;s the most precise clue.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;        meta &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt; getattr&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;__class__&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;__pydantic_generic_metadata__&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;, &lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;None&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; meta &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;and&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; meta.get(&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;args&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;            # We found it! Let&apos;s make it readable.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; pretty_type_name(meta[&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;args&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;][&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;0&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;])&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;        # 2. No metadata? Let&apos;s check the field&apos;s public annotation.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;        #    Pydantic often updates this for us on the specialized class.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;        field_annotation &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;.&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;__class__&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;.model_fields[&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;content&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;].annotation&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;        if&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; field_annotation &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;is&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt; not&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; T: &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# Make sure it&apos;s not just the unspecialized TypeVar&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;            return&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; pretty_type_name(field_annotation)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;        # 3. If we&apos;re still here, it means the model was likely not parameterized&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;        #    (e.g., Message(content=123)). Our only source of truth is the&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;        #    actual value.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt; self&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;.runtime_type&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8250DF;--shiki-dark:#D2A8FF&quot;&gt;    @computed_field&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#8250DF;--shiki-dark:#D2A8FF&quot;&gt;    @&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;property&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;    def&lt;/span&gt;&lt;span style=&quot;color:#8250DF;--shiki-dark:#D2A8FF&quot;&gt; runtime_type&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(self) -&gt; &lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;str&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;        &quot;&quot;&quot;The value-time type. What is the type of the content right now?&quot;&quot;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;        return&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; pretty_type_name(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;type&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;self&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;.content))&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Let’s test our detective kit:&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-default github-dark-default&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#0d1117;color:#1f2328;--shiki-dark:#e6edf3; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# Create a specialized class&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;IntMessage &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; Message[&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;int&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;msg1 &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; IntMessage(&lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;123&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;Param Type: &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;msg1.param_type&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)     &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# -&gt; &quot;int&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;Runtime Type: &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;msg1.runtime_type&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)   &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# -&gt; &quot;int&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# Create a generic message where the value is the only truth&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;msg2 &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; Message(&lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt;content&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;hello&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;Param Type: &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;msg2.param_type&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)     &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# -&gt; &quot;str&quot; (falls back to runtime_type)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;f&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;Runtime Type: &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;{&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;msg2.runtime_type&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;}&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&quot;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;)   &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# -&gt; &quot;str&quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It works! This three-layer strategy is robust. It prefers the precise design-time information when available, but gracefully falls back to the undeniable truth of the runtime value.&lt;/p&gt;
&lt;h2 id=&quot;side-quest-taming-forward-refs-and-circular-nightmares&quot;&gt;Side Quest: Taming Forward Refs and Circular Nightmares&lt;/h2&gt;
&lt;p&gt;Sometimes, you have to define models that refer to each other before they’re fully defined. This is common in things like ORMs or complex API schemas.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-default github-dark-default&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#0d1117;color:#1f2328;--shiki-dark:#e6edf3; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt; A&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;BaseModel&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;    b: &lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&apos;B&apos;&lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;  # &apos;B&apos; isn&apos;t defined yet! This is a &quot;forward reference&quot;.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;class&lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt; B&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;BaseModel&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;    a: &lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&apos;A&apos;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This creates a paradox. How can Python understand &lt;code&gt;A&lt;/code&gt; without knowing &lt;code&gt;B&lt;/code&gt;, and vice-versa? The string &lt;code&gt;&apos;B&apos;&lt;/code&gt; is like an IOU for a type. The problem is that when it’s time to cash in that IOU, Python needs to know &lt;em&gt;where to look&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;If your models are defined inside a function, the names &lt;code&gt;A&lt;/code&gt; and &lt;code&gt;B&lt;/code&gt; might only exist in that function’s local scope. When you try to resolve the types later from a different scope, Python can’t find them.&lt;/p&gt;
&lt;p&gt;The solution is to give Python a map. You capture the namespace (the dictionary of local and global names) where the models were defined and provide it when you ask for the type hints.&lt;/p&gt;
&lt;pre class=&quot;astro-code astro-code-themes github-light-default github-dark-default&quot; style=&quot;background-color:#ffffff;--shiki-dark-bg:#0d1117;color:#1f2328;--shiki-dark:#e6edf3; overflow-x: auto;&quot; tabindex=&quot;0&quot; data-language=&quot;python&quot;&gt;&lt;code&gt;&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;from&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; typing &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;import&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; get_type_hints&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;def&lt;/span&gt;&lt;span style=&quot;color:#8250DF;--shiki-dark:#D2A8FF&quot;&gt; create_circular_models&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;():&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt; A&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;BaseModel&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;        b: &lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&apos;B&apos;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;    class&lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt; B&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;BaseModel&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;        a: A&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;    # Capture the &quot;map&quot; of names available right here, right now.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;    local_namespace &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt; locals&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;()&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;    # Later, from anywhere, you can resolve the types using the map.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;    hints_A &lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt; get_type_hints(A, &lt;/span&gt;&lt;span style=&quot;color:#953800;--shiki-dark:#FFA657&quot;&gt;localns&lt;/span&gt;&lt;span style=&quot;color:#CF222E;--shiki-dark:#FF7B72&quot;&gt;=&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;local_namespace)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#0550AE;--shiki-dark:#79C0FF&quot;&gt;    print&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;(hints_A[&lt;/span&gt;&lt;span style=&quot;color:#0A3069;--shiki-dark:#A5D6FF&quot;&gt;&apos;b&apos;&lt;/span&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;]) &lt;/span&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;# --&gt; &amp;#x3C;class &apos;__main__.create_circular_models.&amp;#x3C;locals&gt;.B&apos;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#6E7781;--shiki-dark:#8B949E&quot;&gt;    # It worked!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;line&quot;&gt;&lt;span style=&quot;color:#1F2328;--shiki-dark:#E6EDF3&quot;&gt;create_circular_models()&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If you keep your models at the top level of a module, you often don’t need to worry about this, as Python’s default global scope is usually enough. But the moment you start defining models inside functions, this &lt;code&gt;localns&lt;/code&gt; trick is a lifesaver.&lt;/p&gt;
&lt;h2 id=&quot;your-new-mental-model&quot;&gt;Your New Mental Model&lt;/h2&gt;
&lt;p&gt;Stop asking, “Why won’t Python give me the type?” Start asking:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;What am I inspecting (a blueprint, a class, or a value), and do I have the right map (the scope) to find what I’m looking for?&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;With this mental model, runtime type introspection stops being a frustrating mystery and becomes a straightforward process of investigation. Your Pydantic generics will no longer feel like a black box, but a powerful tool you can confidently inspect and understand.&lt;/p&gt;
&lt;p&gt;(Written by Human, improved using AI where applicable.)&lt;/p&gt;</description><pubDate>Tue, 16 Sep 2025 00:00:00 GMT</pubDate></item></channel></rss>