Advanced Python Vocabulary: Async, Type Hints, and Modern Python Features

Learn the English vocabulary senior Python developers use in code reviews and architecture discussions — async/await, coroutines, Protocols, TypedDict, descriptors, metaclasses, and GIL tradeoffs.

Senior Python roles demand fluency in a layer of vocabulary that beginners rarely encounter: coroutines, descriptors, structural subtyping, metaclasses. In code reviews, architecture discussions, and technical interviews, using these terms precisely signals that you understand Python deeply — not just syntactically but semantically. This guide targets the vocabulary gap between “writes Python daily” and “thinks in Python.”

Asynchronous Python

async/await is Python’s syntax for writing asynchronous code. A function defined with async def is a coroutine function; calling it returns a coroutine object. A coroutine is a function that can suspend its execution and yield control back to the event loop while waiting for I/O.

The event loop is the scheduler that manages coroutine execution — it runs coroutines, handles I/O callbacks, and dispatches tasks. The standard library provides asyncio; uvloop is a faster drop-in replacement built on libuv. Engineers say: “Switch the server to uvloop — it gives us roughly 2x throughput on I/O-bound workloads.”

A generator is a function that uses yield to produce values lazily. An async generator uses async def and yield together, producing values asynchronously. These are distinct: generators are synchronous; async generators are consumed with async for.

An async context manager implements __aenter__ and __aexit__ and is used with async with. “The database connection pool exposes an async context manager — always use it, never call acquire/release manually.”

Type System Vocabulary

Python’s type hint system has grown significantly. Key terms senior developers use:

Protocol (from typing) defines structural subtyping — a class satisfies a Protocol if it has the required methods and attributes, regardless of inheritance. This is sometimes called “duck typing with type annotations.” “Use a Protocol here instead of an ABC — we don’t want to force callers to inherit from our class.”

TypedDict defines a dictionary with specific, typed keys. It is used where a dataclass would be over-engineered or where JSON-like structures need type safety.

Literal constrains a value to a specific set of constants: Literal["GET", "POST", "PUT"]. TypeVar defines a generic type variable. ParamSpec captures the parameter specification of a callable — used to write decorators that preserve the signature of the wrapped function.

Engineers in code reviews write: “The return type annotation here should be TypeVar bound to Sequence — you’re losing type information by annotating as list.”

Data Classes and the Object Model

dataclass (from dataclasses) generates __init__, __repr__, and __eq__ automatically from class annotations. The ecosystem has two popular alternatives: attrs (more powerful, predates dataclasses) and Pydantic (adds runtime validation — every field is validated when an instance is created, not just type-checked statically).

A descriptor is an object that customises attribute access by implementing __get__, __set__, or __delete__. Properties are the most familiar descriptor. Engineers who understand descriptors can reason about how ORMs, Pydantic, and dataclasses work under the hood.

A metaclass is a class whose instances are classes. Metaclasses intercept class creation and can modify class attributes, register subclasses, or enforce constraints. They are powerful and complex; the common interview question is: “When would you use a metaclass over a class decorator?”

Concurrency Model

The GIL (Global Interpreter Lock) is a mutex in CPython that prevents multiple native threads from executing Python bytecode simultaneously. This means multithreading in Python does not provide parallelism for CPU-bound work — only one thread runs Python at a time.

The tradeoffs:

  • asyncio — best for I/O-bound workloads; single-threaded, no GIL overhead, high concurrency through cooperative multitasking
  • threading — useful for I/O-bound work that uses blocking libraries not compatible with asyncio; limited by the GIL for CPU-bound work
  • multiprocessing — sidesteps the GIL by using separate processes; best for CPU-bound parallelism but has higher overhead for IPC

Engineers frame this precisely: “Don’t use threading for this — the GIL will serialise the CPU-bound transformations. Use multiprocessing with a pool, or push the work to a worker service.”

Real PR Comment Examples

  • “This coroutine is being called without await — it will never execute.”
  • “Replace this dict annotation with TypedDict — we need the keys to be statically checkable.”
  • “The decorator loses the wrapped function’s signature — use functools.wraps and add a ParamSpec to preserve it.”
  • “This metaclass is doing too much — consider whether a class decorator achieves the same goal with less magic.”

Next Steps

Pick one concept from this article that you feel least confident about and write a 10-line Python snippet that demonstrates it — with a docstring in English explaining what it does and why. Then read the CPython source for the relevant module (asyncio, dataclasses, typing) for 20 minutes. Reading implementation code is the fastest path to owning advanced vocabulary.