Skip to content

Commit

Permalink
Make __parameters__ lazy (python#15)
Browse files Browse the repository at this point in the history
Now we can also remove `__setstate__`.
  • Loading branch information
ethanhs authored Feb 25, 2020
1 parent 4783c2e commit e50136d
Showing 1 changed file with 31 additions and 19 deletions.
50 changes: 31 additions & 19 deletions Objects/descrobject.c
Original file line number Diff line number Diff line change
Expand Up @@ -1969,6 +1969,15 @@ static PyObject *
ga_getitem(PyObject *self, PyObject *item)
{
gaobject *alias = (gaobject *)self;
// do a lookup for __parameters__ so it gets populated (if not already)
if (alias->parameters == NULL) {
_Py_IDENTIFIER(__parameters__);
PyObject *params = _PyObject_GetAttrId(self, &PyId___parameters__);
if (params == NULL) {
return NULL;
}
Py_DECREF(params);
}
Py_ssize_t nparams = PyTuple_GET_SIZE(alias->parameters);
if (nparams == 0) {
return PyErr_Format(PyExc_TypeError,
Expand Down Expand Up @@ -2031,7 +2040,6 @@ static const char* const attr_exceptions[] = {
"__mro_entries__",
"__reduce_ex__", // needed so we don't look up object.__reduce_ex__
"__reduce__",
"__setstate__",
NULL,
};

Expand Down Expand Up @@ -2118,29 +2126,37 @@ ga_reduce(PyObject *self, PyObject *Py_UNUSED(ignored))
alias->origin, alias->args);
}

static PyObject *
ga_setstate(PyObject *self, PyObject *state)
{
gaobject *alias = (gaobject *)self;
PyObject *parameters = make_parameters(alias->args);
Py_INCREF(parameters);
alias->parameters = parameters;
Py_RETURN_NONE;
}

static PyMethodDef ga_methods[] = {
{"__mro_entries__", ga_mro_entries, METH_O},
{"__instancecheck__", ga_instancecheck, METH_O},
{"__subclasscheck__", ga_subclasscheck, METH_O},
{"__reduce__", ga_reduce, METH_NOARGS},
{"__setstate__", ga_setstate, METH_O},
{0}
};

static PyMemberDef ga_members[] = {
{"__origin__", T_OBJECT, offsetof(gaobject, origin), READONLY},
{"__args__", T_OBJECT, offsetof(gaobject, args), READONLY},
{"__parameters__", T_OBJECT, offsetof(gaobject, parameters), READONLY},
{0}
};

static PyObject *
ga_parameters(PyObject *self, void *unused)
{
gaobject *alias = (gaobject *)self;
if (alias->parameters == NULL) {
alias->parameters = make_parameters(alias->args);
if (alias->parameters == NULL) {
Py_DECREF(alias->parameters);
return NULL;
}
}
Py_INCREF(alias->parameters);
return alias->parameters;
}

static PyGetSetDef ga_properties[] = {
{"__parameters__", ga_parameters, (setter)NULL, "Type variables in the GenericAlias.", NULL},
{0}
};

Expand Down Expand Up @@ -2179,6 +2195,7 @@ PyTypeObject Py_GenericAliasType = {
.tp_alloc = PyType_GenericAlloc,
.tp_new = ga_new,
.tp_free = PyObject_GC_Del,
.tp_getset = ga_properties,
};

PyObject *
Expand All @@ -2203,12 +2220,7 @@ Py_GenericAlias(PyObject *origin, PyObject *args)
Py_INCREF(origin);
alias->origin = origin;
alias->args = args;
// TODO: Make __parameters__ a lazy attribute
alias->parameters = make_parameters(args);
if (alias->parameters == NULL) {
Py_DECREF(alias);
return NULL;
}
alias->parameters = NULL;
_PyObject_GC_TRACK(alias);
return (PyObject *)alias;
}

0 comments on commit e50136d

Please sign in to comment.