Skip to main content

Objects/genericaliasobject.c

Source:

cpython 3.14 @ ab2d84fe1023/Objects/genericaliasobject.c

Map

LinesSymbolWhat it does
1-40struct gaobjectStruct layout: origin, args, weakreflist, starred flag
41-90Ga_newAllocates a new gaobject from (origin, args) pair
91-150ga_origin_getorigin getter: returns origin field (e.g. list)
151-200ga_args_getargs getter: returns args tuple (e.g. (int,))
201-270ga_getitemgetitem: substitutes type variables, returns new gaobject
271-330ga_instancecheckinstancecheck: always raises TypeError
331-380ga_subclasschecksubclasscheck: always raises TypeError
381-430ga_class_getitemclass_getitem: entry point for list[int] syntax
431-500Py_GenericAliasPublic C API for creating generic alias objects

Reading

gaobject layout and construction

A gaobject is the runtime object produced by expressions like list[int] or dict[str, int]. It holds the origin type and the argument tuple. The starred flag is set for *args-style unpacked type expressions introduced in PEP 646.

// CPython: Objects/genericaliasobject.c:18 gaobject
typedef struct {
PyObject_HEAD
PyObject *origin;
PyObject *args;
PyObject *parameters; /* cached tuple of free TypeVars */
PyObject *weakreflist;
int starred;
} gaobject;

Ga_new is the canonical allocator. It accepts an origin object and an args tuple. When called with a single non-tuple argument, it wraps it in a one-element tuple first. The resulting object is immutable: neither field has a setter.

// CPython: Objects/genericaliasobject.c:52 Ga_new
PyObject *
Py_GenericAlias(PyObject *origin, PyObject *args)
{
if (!PyTuple_Check(args)) {
args = PyTuple_Pack(1, args);
if (args == NULL)
return NULL;
}
...
ga->origin = Py_NewRef(origin);
ga->args = Py_NewRef(args);
return (PyObject *)ga;
}

origin and args accessors

Both attributes are exposed as plain descriptors on PyGenericAlias_Type. The getters simply return the stored field with a new reference. Neither attribute is settable, matching the immutability guarantee of generic alias objects.

// CPython: Objects/genericaliasobject.c:93 ga_origin_get
static PyObject *
ga_origin_get(gaobject *self, void *unused)
{
return Py_NewRef(self->origin);
}

// CPython: Objects/genericaliasobject.c:154 ga_args_get
static PyObject *
ga_args_get(gaobject *self, void *unused)
{
return Py_NewRef(self->args);
}

getitem, isinstance checks, and class_getitem

ga_getitem handles nested parameterization (e.g. list[T][int]). It substitutes free type variables from self->parameters with the supplied arguments, returning a new gaobject.

ga_instancecheck and ga_subclasscheck both unconditionally raise TypeError. This is intentional: isinstance(x, list[int]) is not supported at runtime and the error message tells the user to use isinstance(x, list) instead.

// CPython: Objects/genericaliasobject.c:273 ga_instancecheck
static PyObject *
ga_instancecheck(PyObject *self, PyObject *instance)
{
PyErr_SetString(PyExc_TypeError,
"isinstance() argument 2 cannot be a parameterized generic");
return NULL;
}

ga_class_getitem is the entry point registered as __class_getitem__ on built-in types like list and dict. When Python evaluates list[int], the interpreter calls list.__class_getitem__(int), which calls Py_GenericAlias(list, int).

gopy notes

Status: not yet ported.

Planned package path: objects/generic_alias.go.

A stub GenericAlias type exists in objects/generic_alias.go (added on the current branch) but the full attribute set, __getitem__ substitution, and the TypeError-raising isinstance checks are not yet implemented. The __class_getitem__ wiring is needed for list, dict, tuple, and other built-in collection types to accept subscript syntax in type annotations.