]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
bpo-40521: Empty frozenset is no longer a singleton (GH-21085)
authorRaymond Hettinger <rhettinger@users.noreply.github.com>
Tue, 23 Jun 2020 15:42:55 +0000 (08:42 -0700)
committerGitHub <noreply@github.com>
Tue, 23 Jun 2020 15:42:55 +0000 (17:42 +0200)
* Revert "bpo-40521: Make the empty frozenset per interpreter (GH-21068)"

This reverts commit 261cfedf7657a515e04428bba58eba2a9bb88208.

* bpo-40521: Empty frozensets are no longer singletons

* Complete the removal of the frozenset singleton

Include/internal/pycore_interp.h
Include/internal/pycore_pylifecycle.h
Lib/test/test_marshal.py
Lib/test/test_set.py
Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst
Misc/NEWS.d/next/Core and Builtins/2020-06-23-07-35-11.bpo-40521.dMNA6k.rst [new file with mode: 0644]
Objects/setobject.c
Python/pylifecycle.c

index 64e891f9f6eb4d6466ecf297e6a11863515e7cdd..c22bea75d2795cb176d033d0042788fc3732357f 100644 (file)
@@ -244,8 +244,6 @@ struct _is {
     /* Using a cache is very effective since typically only a single slice is
        created and then deleted again. */
     PySliceObject *slice_cache;
-    // The empty frozenset is a singleton.
-    PyObject *empty_frozenset;
 
     struct _Py_tuple_state tuple;
     struct _Py_list_state list;
index 9a3063aa2775f07d1861c96d10a87529eb07ac3b..30ba48423f9ec4da3faa2ba918b018417a21e805 100644 (file)
@@ -62,7 +62,6 @@ extern void _PyFrame_Fini(PyThreadState *tstate);
 extern void _PyDict_Fini(PyThreadState *tstate);
 extern void _PyTuple_Fini(PyThreadState *tstate);
 extern void _PyList_Fini(PyThreadState *tstate);
-extern void _PySet_Fini(PyThreadState *tstate);
 extern void _PyBytes_Fini(PyThreadState *tstate);
 extern void _PyFloat_Fini(PyThreadState *tstate);
 extern void _PySlice_Fini(PyThreadState *tstate);
index ace1593999d4ebf9ea05adc29fdde378f3f31735..b7f4dbb98e36d4c4af8db00cee89dc8bc511f1ab 100644 (file)
@@ -158,13 +158,6 @@ class ContainerTestCase(unittest.TestCase, HelperMixin):
         for constructor in (set, frozenset):
             self.helper(constructor(self.d.keys()))
 
-    @support.cpython_only
-    def test_empty_frozenset_singleton(self):
-        # marshal.loads() must reuse the empty frozenset singleton
-        obj = frozenset()
-        obj2 = marshal.loads(marshal.dumps(obj))
-        self.assertIs(obj2, obj)
-
 
 class BufferTestCase(unittest.TestCase, HelperMixin):
 
index 9851a998983f83b7f99108d8baf8cc1d6aca5eff..68d494213e58702d3d36c9537ed2accbf9042d21 100644 (file)
@@ -661,15 +661,6 @@ class TestFrozenSet(TestJointOps, unittest.TestCase):
         s.__init__(self.otherword)
         self.assertEqual(s, set(self.word))
 
-    def test_singleton_empty_frozenset(self):
-        f = frozenset()
-        efs = [frozenset(), frozenset([]), frozenset(()), frozenset(''),
-               frozenset(), frozenset([]), frozenset(()), frozenset(''),
-               frozenset(range(0)), frozenset(frozenset()),
-               frozenset(f), f]
-        # All of the empty frozensets should have just one id()
-        self.assertEqual(len(set(map(id, efs))), 1)
-
     def test_constructor_identity(self):
         s = self.thetype(range(3))
         t = self.thetype(s)
index 95fab369748f0a7b162723101765277ffd590101..a62383d2093ecdfd0cbfaa66a96d2a1164b3bf7f 100644 (file)
@@ -2,8 +2,9 @@ Each interpreter now its has own free lists, singletons and caches:
 
 * Free lists: float, tuple, list, dict, frame, context,
   asynchronous generator.
-* Singletons: empty tuple, empty frozenset, empty bytes string,
+* Singletons: empty tuple, empty bytes string,
   single byte character.
 * Slice cache.
 
 They are no longer shared by all interpreters.
+
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-06-23-07-35-11.bpo-40521.dMNA6k.rst b/Misc/NEWS.d/next/Core and Builtins/2020-06-23-07-35-11.bpo-40521.dMNA6k.rst
new file mode 100644 (file)
index 0000000..25f146e
--- /dev/null
@@ -0,0 +1 @@
+Empty frozensets are no longer singletons.
index 69bfc7d0a58fb23c1cf72e682fe8ca2add7a84ec..b2711495b657bdea826e7c9bf6eea8c1621319ce 100644 (file)
@@ -978,38 +978,16 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
 static PyObject *
 make_new_frozenset(PyTypeObject *type, PyObject *iterable)
 {
-    PyObject *res;
-
     if (type != &PyFrozenSet_Type) {
         return make_new_set(type, iterable);
     }
 
-    if (iterable != NULL) {
-        if (PyFrozenSet_CheckExact(iterable)) {
-            /* frozenset(f) is idempotent */
-            Py_INCREF(iterable);
-            return iterable;
-        }
-        res = make_new_set((PyTypeObject *)type, iterable);
-        if (res == NULL || PySet_GET_SIZE(res) != 0) {
-            return res;
-        }
-        /* If the created frozenset is empty, return the empty frozenset singleton instead */
-        Py_DECREF(res);
+    if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) {
+        /* frozenset(f) is idempotent */
+        Py_INCREF(iterable);
+        return iterable;
     }
-
-    // The empty frozenset is a singleton
-    PyInterpreterState *interp = _PyInterpreterState_GET();
-    res = interp->empty_frozenset;
-    if (res == NULL) {
-        interp->empty_frozenset = make_new_set((PyTypeObject *)type, NULL);
-        res = interp->empty_frozenset;
-        if (res == NULL) {
-            return NULL;
-        }
-    }
-    Py_INCREF(res);
-    return res;
+    return make_new_set((PyTypeObject *)type, iterable);
 }
 
 static PyObject *
@@ -2304,12 +2282,6 @@ PySet_Add(PyObject *anyset, PyObject *key)
     return set_add_key((PySetObject *)anyset, key);
 }
 
-void
-_PySet_Fini(PyThreadState *tstate)
-{
-    Py_CLEAR(tstate->interp->empty_frozenset);
-}
-
 int
 _PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
 {
index f0770727f4de713a9147e27ed9f90ee3f97a9905..09945a8f7a6a07f622f881625c7b02e67511fb7f 100644 (file)
@@ -1253,7 +1253,6 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp)
     _PyAsyncGen_Fini(tstate);
     _PyContext_Fini(tstate);
 
-    _PySet_Fini(tstate);
     _PyDict_Fini(tstate);
     _PyList_Fini(tstate);
     _PyTuple_Fini(tstate);