Skip to content

Commit e50136d

Browse files
authored
Make __parameters__ lazy (python#15)
Now we can also remove `__setstate__`.
1 parent 4783c2e commit e50136d

File tree

1 file changed

+31
-19
lines changed

1 file changed

+31
-19
lines changed

Objects/descrobject.c

Lines changed: 31 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1969,6 +1969,15 @@ static PyObject *
19691969
ga_getitem(PyObject *self, PyObject *item)
19701970
{
19711971
gaobject *alias = (gaobject *)self;
1972+
// do a lookup for __parameters__ so it gets populated (if not already)
1973+
if (alias->parameters == NULL) {
1974+
_Py_IDENTIFIER(__parameters__);
1975+
PyObject *params = _PyObject_GetAttrId(self, &PyId___parameters__);
1976+
if (params == NULL) {
1977+
return NULL;
1978+
}
1979+
Py_DECREF(params);
1980+
}
19721981
Py_ssize_t nparams = PyTuple_GET_SIZE(alias->parameters);
19731982
if (nparams == 0) {
19741983
return PyErr_Format(PyExc_TypeError,
@@ -2031,7 +2040,6 @@ static const char* const attr_exceptions[] = {
20312040
"__mro_entries__",
20322041
"__reduce_ex__", // needed so we don't look up object.__reduce_ex__
20332042
"__reduce__",
2034-
"__setstate__",
20352043
NULL,
20362044
};
20372045

@@ -2118,29 +2126,37 @@ ga_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
21182126
alias->origin, alias->args);
21192127
}
21202128

2121-
static PyObject *
2122-
ga_setstate(PyObject *self, PyObject *state)
2123-
{
2124-
gaobject *alias = (gaobject *)self;
2125-
PyObject *parameters = make_parameters(alias->args);
2126-
Py_INCREF(parameters);
2127-
alias->parameters = parameters;
2128-
Py_RETURN_NONE;
2129-
}
2130-
21312129
static PyMethodDef ga_methods[] = {
21322130
{"__mro_entries__", ga_mro_entries, METH_O},
21332131
{"__instancecheck__", ga_instancecheck, METH_O},
21342132
{"__subclasscheck__", ga_subclasscheck, METH_O},
21352133
{"__reduce__", ga_reduce, METH_NOARGS},
2136-
{"__setstate__", ga_setstate, METH_O},
21372134
{0}
21382135
};
21392136

21402137
static PyMemberDef ga_members[] = {
21412138
{"__origin__", T_OBJECT, offsetof(gaobject, origin), READONLY},
21422139
{"__args__", T_OBJECT, offsetof(gaobject, args), READONLY},
2143-
{"__parameters__", T_OBJECT, offsetof(gaobject, parameters), READONLY},
2140+
{0}
2141+
};
2142+
2143+
static PyObject *
2144+
ga_parameters(PyObject *self, void *unused)
2145+
{
2146+
gaobject *alias = (gaobject *)self;
2147+
if (alias->parameters == NULL) {
2148+
alias->parameters = make_parameters(alias->args);
2149+
if (alias->parameters == NULL) {
2150+
Py_DECREF(alias->parameters);
2151+
return NULL;
2152+
}
2153+
}
2154+
Py_INCREF(alias->parameters);
2155+
return alias->parameters;
2156+
}
2157+
2158+
static PyGetSetDef ga_properties[] = {
2159+
{"__parameters__", ga_parameters, (setter)NULL, "Type variables in the GenericAlias.", NULL},
21442160
{0}
21452161
};
21462162

@@ -2179,6 +2195,7 @@ PyTypeObject Py_GenericAliasType = {
21792195
.tp_alloc = PyType_GenericAlloc,
21802196
.tp_new = ga_new,
21812197
.tp_free = PyObject_GC_Del,
2198+
.tp_getset = ga_properties,
21822199
};
21832200

21842201
PyObject *
@@ -2203,12 +2220,7 @@ Py_GenericAlias(PyObject *origin, PyObject *args)
22032220
Py_INCREF(origin);
22042221
alias->origin = origin;
22052222
alias->args = args;
2206-
// TODO: Make __parameters__ a lazy attribute
2207-
alias->parameters = make_parameters(args);
2208-
if (alias->parameters == NULL) {
2209-
Py_DECREF(alias);
2210-
return NULL;
2211-
}
2223+
alias->parameters = NULL;
22122224
_PyObject_GC_TRACK(alias);
22132225
return (PyObject *)alias;
22142226
}

0 commit comments

Comments
 (0)