Skip to content
tezvyn:

Accessing Python Type Annotations Safely

Source: docs.python.orgHardHow cards are made

Accessing Python Type Annotations Safely

Accessing an object's type hints isn't just obj.__annotations__. Use inspect.get_annotations() in Python 3.10+ for safe access. This is key for tools like FastAPI that introspect your code.

Why it exists

Python needed a standard way for tools to read the type hints and other metadata developers attach to code. Frameworks like FastAPI, Pydantic, and Typer rely on this introspection to automate validation and serialization. However, the initial implementation had subtle issues, necessitating a standardized, safer access method.

The mental model

Think of annotations as a raw dictionary attached to an object, but with tricky inheritance rules in older Python versions. Instead of accessing this raw data directly, use a dedicated "getter" function like inspect.get_annotations() as your official, safe API. This function acts as a compatibility layer, shielding you from version-specific implementation details.

How it works

The recommended approach varies by Python version. In Python 3.10 and newer, the best practice is to call inspect.get_annotations(obj). This function correctly handles different object types and can "un-stringize" forward references. If you must access the dictionary directly, obj.annotations is now guaranteed to work correctly for functions, classes, and modules. For other callables, use getattr(obj, 'annotations', None). In Python 3.9 and older, the logic is more complex. For non-class objects, getattr is safe. For classes, you must check the class's dict directly (MyClass.dict.get('annotations')) to avoid accidentally inheriting annotations from a parent class.

When to use it

Use programmatic access to annotations when building tools that need to understand code structure at runtime. This is common in dependency injection systems (FastAPI), data validation libraries (Pydantic), and CLI tools (Typer). These frameworks inspect function and class annotations to automate their core logic.

When not to use it

Avoid manually accessing the annotations dunder attribute directly, especially in code supporting multiple Python versions. Always prefer the highest-level abstraction available: inspect.get_annotations() in Python 3.10+ and annotationlib.get_annotations() in 3.14+. Direct access is a low-level operation prone to breaking.

One canonical example

The classic footgun in Python 3.9 and earlier involves class inheritance. Given class Base: a: int and class Derived(Base): pass, running print(Derived.annotations) in Python 3.9 would output {'a': <class 'int'>}, the parent's dictionary. In Python 3.10+, the same code correctly prints an empty dictionary, {}, because Derived has no annotations of its own, making introspection more predictable.

Interview question

What specific problem did direct access to "__annotations__" for a class, like "Derived.__annotations__", commonly cause in Python 3.9 that "inspect.get_annotations()" addresses in Python 3.10+?

  • a.It raised an AttributeError if the class itself did not define any annotations, requiring a default value.
  • b.It failed to resolve string-based forward references, returning them as raw strings instead of evaluated types.
  • c.It would incorrectly show annotations inherited from a parent class, even if the derived class had no explicit annotations.Correct
  • d.It could not access annotations for class methods or static methods, only for instance attributes.
Why?

In Python 3.9 and earlier, direct access to a class's __annotations__ would incorrectly include annotations inherited from parent classes. Python 3.10+ and `inspect.get_annotations()` resolve this by ensuring a class's __annotations__ only contains its own explicitly defined annotations, returning an empty dictionary if none are present.

Just read this? Test yourself on what you have been reading.

Read the original → docs.python.org

You just looked this up. Could you explain it out loud?

That is the part interviews actually test. Tezvyn takes questions like this one and gives you what the interviewer is really checking, the answer that lands, and the mistake that ends the conversation, in the four minutes before your next meeting.

The iPhone app is on the way

We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.

Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.

Get it on Google PlayiPhone app coming soon

We are hiring for this. Open roles that interview on python — each one lists the topics its interview covers.

See open roles