[Python-checkins] bpo-46417: Add _PyType_GetSubclasses() function (GH-30761)

vstinner webhook-mailer at python.org
Fri Jan 21 17:29:21 EST 2022


https://github.com/python/cpython/commit/8ee07dda139f3fa1d7c58a29532a98efc790568d
commit: 8ee07dda139f3fa1d7c58a29532a98efc790568d
branch: main
author: Victor Stinner <vstinner at python.org>
committer: vstinner <vstinner at python.org>
date: 2022年01月21日T23:29:10+01:00
summary:
bpo-46417: Add _PyType_GetSubclasses() function (GH-30761)
Add a new _PyType_GetSubclasses() function to get type's subclasses.
_PyType_GetSubclasses(type) returns a list which holds strong
refererences to subclasses. It is safer than iterating on
type->tp_subclasses which yields weak references and can be modified
in the loop.
_PyType_GetSubclasses(type) now holds a reference to the tp_subclasses
dict while creating the list of subclasses.
set_collection_flag_recursive() of _abc.c now uses
_PyType_GetSubclasses().
files:
M Include/internal/pycore_object.h
M Modules/_abc.c
M Objects/typeobject.c
diff --git a/Include/internal/pycore_object.h b/Include/internal/pycore_object.h
index 0348563218072..be308cd25d710 100644
--- a/Include/internal/pycore_object.h
+++ b/Include/internal/pycore_object.h
@@ -220,11 +220,12 @@ static inline PyObject **_PyObject_ManagedDictPointer(PyObject *obj)
 return ((PyObject **)obj)-3;
 }
 
-PyObject ** _PyObject_DictPointer(PyObject *);
-int _PyObject_VisitInstanceAttributes(PyObject *self, visitproc visit, void *arg);
-void _PyObject_ClearInstanceAttributes(PyObject *self);
-void _PyObject_FreeInstanceAttributes(PyObject *self);
-int _PyObject_IsInstanceDictEmpty(PyObject *);
+extern PyObject ** _PyObject_DictPointer(PyObject *);
+extern int _PyObject_VisitInstanceAttributes(PyObject *self, visitproc visit, void *arg);
+extern void _PyObject_ClearInstanceAttributes(PyObject *self);
+extern void _PyObject_FreeInstanceAttributes(PyObject *self);
+extern int _PyObject_IsInstanceDictEmpty(PyObject *);
+extern PyObject* _PyType_GetSubclasses(PyTypeObject *);
 
 #ifdef __cplusplus
 }
diff --git a/Modules/_abc.c b/Modules/_abc.c
index b7465c379dddf..a043961812041 100644
--- a/Modules/_abc.c
+++ b/Modules/_abc.c
@@ -4,6 +4,7 @@
 #endif
 
 #include "Python.h"
+#include "pycore_object.h" // _PyType_GetSubclasses()
 #include "pycore_moduleobject.h" // _PyModule_GetState()
 #include "clinic/_abc.c.h"
 
@@ -493,21 +494,20 @@ set_collection_flag_recursive(PyTypeObject *child, unsigned long flag)
 {
 return;
 }
+
 child->tp_flags &= ~COLLECTION_FLAGS;
 child->tp_flags |= flag;
- PyObject *grandchildren = child->tp_subclasses;
+
+ PyObject *grandchildren = _PyType_GetSubclasses(child);
 if (grandchildren == NULL) {
 return;
 }
- assert(PyDict_CheckExact(grandchildren));
- Py_ssize_t i = 0;
- while (PyDict_Next(grandchildren, &i, NULL, &grandchildren)) {
- assert(PyWeakref_CheckRef(grandchildren));
- PyObject *grandchild = PyWeakref_GET_OBJECT(grandchildren);
- if (PyType_Check(grandchild)) {
- set_collection_flag_recursive((PyTypeObject *)grandchild, flag);
- }
+
+ for (Py_ssize_t i = 0; i < PyList_GET_SIZE(grandchildren); i++) {
+ PyObject *grandchild = PyList_GET_ITEM(grandchildren, i);
+ set_collection_flag_recursive((PyTypeObject *)grandchild, flag);
 }
+ Py_DECREF(grandchildren);
 }
 
 /*[clinic input]
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index c46c3d80edbaa..e4a4824fa2e41 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -687,27 +687,28 @@ static int recurse_down_subclasses(PyTypeObject *type, PyObject *name,
 static int
 mro_hierarchy(PyTypeObject *type, PyObject *temp)
 {
- int res;
- PyObject *new_mro, *old_mro;
- PyObject *tuple;
- PyObject *subclasses;
- Py_ssize_t i, n;
-
- res = mro_internal(type, &old_mro);
- if (res <= 0)
+ PyObject *old_mro;
+ int res = mro_internal(type, &old_mro);
+ if (res <= 0) {
 /* error / reentrance */
 return res;
- new_mro = type->tp_mro;
+ }
+ PyObject *new_mro = type->tp_mro;
 
- if (old_mro != NULL)
+ PyObject *tuple;
+ if (old_mro != NULL) {
 tuple = PyTuple_Pack(3, type, new_mro, old_mro);
- else
+ }
+ else {
 tuple = PyTuple_Pack(2, type, new_mro);
+ }
 
- if (tuple != NULL)
+ if (tuple != NULL) {
 res = PyList_Append(temp, tuple);
- else
+ }
+ else {
 res = -1;
+ }
 Py_XDECREF(tuple);
 
 if (res < 0) {
@@ -727,15 +728,18 @@ mro_hierarchy(PyTypeObject *type, PyObject *temp)
 Finally, this makes things simple avoiding the need to deal
 with dictionary iterators and weak references.
 */
- subclasses = type___subclasses___impl(type);
- if (subclasses == NULL)
+ PyObject *subclasses = _PyType_GetSubclasses(type);
+ if (subclasses == NULL) {
 return -1;
- n = PyList_GET_SIZE(subclasses);
- for (i = 0; i < n; i++) {
+ }
+
+ Py_ssize_t n = PyList_GET_SIZE(subclasses);
+ for (Py_ssize_t i = 0; i < n; i++) {
 PyTypeObject *subclass = _PyType_CAST(PyList_GET_ITEM(subclasses, i));
 res = mro_hierarchy(subclass, temp);
- if (res < 0)
+ if (res < 0) {
 break;
+ }
 }
 Py_DECREF(subclasses);
 
@@ -4124,6 +4128,42 @@ type_dealloc(PyTypeObject *type)
 Py_TYPE(type)->tp_free((PyObject *)type);
 }
 
+
+PyObject*
+_PyType_GetSubclasses(PyTypeObject *self)
+{
+ PyObject *list = PyList_New(0);
+ if (list == NULL) {
+ return NULL;
+ }
+
+ // Hold a strong reference to tp_subclasses while iterating on it
+ PyObject *dict = Py_XNewRef(self->tp_subclasses);
+ if (dict == NULL) {
+ return list;
+ }
+ assert(PyDict_CheckExact(dict));
+
+ Py_ssize_t i = 0;
+ PyObject *ref; // borrowed ref
+ while (PyDict_Next(dict, &i, NULL, &ref)) {
+ assert(PyWeakref_CheckRef(ref));
+ PyObject *obj = PyWeakref_GET_OBJECT(ref); // borrowed ref
+ if (obj == Py_None) {
+ continue;
+ }
+ assert(PyType_Check(obj));
+ if (PyList_Append(list, obj) < 0) {
+ Py_CLEAR(list);
+ goto done;
+ }
+ }
+done:
+ Py_DECREF(dict);
+ return list;
+}
+
+
 /*[clinic input]
 type.__subclasses__
 
@@ -4134,28 +4174,7 @@ static PyObject *
 type___subclasses___impl(PyTypeObject *self)
 /*[clinic end generated code: output=eb5eb54485942819 input=5af66132436f9a7b]*/
 {
- PyObject *list, *raw, *ref;
- Py_ssize_t i;
-
- list = PyList_New(0);
- if (list == NULL)
- return NULL;
- raw = self->tp_subclasses;
- if (raw == NULL)
- return list;
- assert(PyDict_CheckExact(raw));
- i = 0;
- while (PyDict_Next(raw, &i, NULL, &ref)) {
- assert(PyWeakref_CheckRef(ref));
- ref = PyWeakref_GET_OBJECT(ref);
- if (ref != Py_None) {
- if (PyList_Append(list, ref) < 0) {
- Py_DECREF(list);
- return NULL;
- }
- }
- }
- return list;
+ return _PyType_GetSubclasses(self);
 }
 
 static PyObject *
@@ -4165,6 +4184,7 @@ type_prepare(PyObject *self, PyObject *const *args, Py_ssize_t nargs,
 return PyDict_New();
 }
 
+
 /*
 Merge the __dict__ of aclass into dict, and recursively also all
 the __dict__s of aclass's base classes. The order of merging isn't


More information about the Python-checkins mailing list

AltStyle によって変換されたページ (->オリジナル) /