Skip to main content

Lib/typing.py (part 4)

Source:

cpython 3.14 @ ab2d84fe1023/Lib/typing.py

This annotation covers structural subtyping and typed container constructors. See lib_typing3_detail for Generic, TypeVar, Union, Optional, and Literal.

Map

LinesSymbolRole
1-100ProtocolStructural subtyping base class
101-200runtime_checkableEnable isinstance for Protocol classes
201-320TypedDictDict subclass with per-key type annotations
321-440NamedTupleNamed tuple with type annotations
441-600dataclass_transformPEP 681 metadata for dataclass-like decorators

Reading

Protocol

# CPython: Lib/typing.py:1820 Protocol
class Protocol(metaclass=_ProtocolMeta):
"""Base class for protocol classes."""
__slots__ = ()
_is_protocol = True
_is_runtime_protocol = False

def __init_subclass__(cls, *args, **kwargs):
super().__init_subclass__(*args, **kwargs)
cls.__protocol_attrs__ = _get_protocol_attrs(cls)

A Protocol class defines a structural interface: any class that has the required attributes/methods satisfies the protocol, without explicitly inheriting from it. __protocol_attrs__ is computed at class creation time from all non-dunder annotations.

runtime_checkable

# CPython: Lib/typing.py:1900 runtime_checkable
def runtime_checkable(cls):
"""Mark a protocol class as a runtime protocol (supports isinstance)."""
if not (isinstance(cls, _ProtocolMeta) and cls._is_protocol):
raise TypeError('@runtime_checkable can be only applied to protocol classes')
cls._is_runtime_protocol = True
return cls

By default isinstance(obj, SomeProtocol) raises TypeError. @runtime_checkable enables it, but only checks for attribute presence (not types). isinstance([], Sized) is True because list has __len__; the type of __len__ is not checked.

TypedDict

# CPython: Lib/typing.py:2480 TypedDict
def TypedDict(typename, fields=None, *, total=True, **kwargs):
"""A simple typed namespace."""
if fields is None:
fields = kwargs
ns = {'__annotations__': dict(fields), '__total__': total}
tp = type(typename, (dict,), ns)
tp.__qualname__ = typename
return tp

TypedDict('Point', {'x': int, 'y': int}) creates a dict subclass with __annotations__. Static type checkers treat it as a typed dict, but at runtime it is just a plain dict. total=False marks all keys as NotRequired.

NamedTuple

# CPython: Lib/typing.py:2620 NamedTuple
def NamedTuple(typename, fields=None, **kwargs):
"""Typed version of collections.namedtuple."""
if fields is None:
fields = kwargs
types = [t for _, t in fields]
return collections.namedtuple(typename, [n for n, _ in fields],
defaults=[...])

class Point(NamedTuple): x: int; y: int at class level uses NamedTupleMeta to call collections.namedtuple with the annotated field names and types. Defaults come from class-level assignments (x: int = 0).

dataclass_transform

# CPython: Lib/typing.py:3020 dataclass_transform
def dataclass_transform(
*,
eq_default: bool = True,
order_default: bool = False,
kw_only_default: bool = False,
frozen_default: bool = False,
field_specifiers: tuple[type | Callable[..., Any], ...] = (),
**kwargs: Any,
) -> Callable[[T], T]:
"""Decorator to mark a class or function as a dataclass-like transformer."""
def decorator(cls_or_fn):
cls_or_fn.__dataclass_transform__ = {
"eq_default": eq_default,
...
"field_specifiers": field_specifiers,
}
return cls_or_fn
return decorator

PEP 681: @dataclass_transform annotates library decorators (like attrs, SQLAlchemy) so type checkers can infer field types. At runtime it only attaches __dataclass_transform__ metadata; the actual transformation is done by the decorated class/function.

gopy notes

Protocol is module/typing.Protocol in module/types/module.go. runtime_checkable sets a flag that objects.IsInstance checks during structural subtype tests. TypedDict creates a subclass of objects.Dict with an annotations dict. NamedTuple delegates to collections.namedtuple. dataclass_transform attaches metadata only.