bpo-42202: Store func annotations as a tuple (GH-23316)

Reduce memory footprint and improve performance of loading modules having many func annotations.

  >>> sys.getsizeof({"a":"int","b":"int","return":"int"})
  232
  >>> sys.getsizeof(("a","int","b","int","return","int"))
  88

The tuple is converted into dict on the fly when `func.__annotations__` is accessed first.

Co-authored-by: Serhiy Storchaka <storchaka@gmail.com>
Co-authored-by: Inada Naoki <songofacandy@gmail.com>
This commit is contained in:
Yurii Karabas 2020-11-25 12:43:18 +02:00 committed by GitHub
parent 85c84920f5
commit 7301979b23
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 174 additions and 155 deletions

View file

@ -424,6 +424,25 @@ func_get_annotations(PyFunctionObject *op, void *Py_UNUSED(ignored))
if (op->func_annotations == NULL)
return NULL;
}
if (PyTuple_CheckExact(op->func_annotations)) {
PyObject *ann_tuple = op->func_annotations;
PyObject *ann_dict = PyDict_New();
if (ann_dict == NULL) {
return NULL;
}
assert(PyTuple_GET_SIZE(ann_tuple) % 2 == 0);
for (Py_ssize_t i = 0; i < PyTuple_GET_SIZE(ann_tuple); i += 2) {
int err = PyDict_SetItem(ann_dict,
PyTuple_GET_ITEM(ann_tuple, i),
PyTuple_GET_ITEM(ann_tuple, i + 1));
if (err < 0)
return NULL;
}
Py_SETREF(op->func_annotations, ann_dict);
}
Py_INCREF(op->func_annotations);
return op->func_annotations;
}