summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRaymond Hettinger <rhettinger@users.noreply.github.com>2020-06-23 15:42:55 (GMT)
committerGitHub <noreply@github.com>2020-06-23 15:42:55 (GMT)
commitf9bd05e83e32bece49de5af0c9a232325c57648a (patch)
treef332a6f5041e64595b8569ca34ae6eb598c8e951
parent522691c46e2ae51faaad5bbbce7d959dd61770df (diff)
downloadcpython-f9bd05e83e32bece49de5af0c9a232325c57648a.zip
cpython-f9bd05e83e32bece49de5af0c9a232325c57648a.tar.gz
cpython-f9bd05e83e32bece49de5af0c9a232325c57648a.tar.bz2
bpo-40521: Empty frozenset is no longer a singleton (GH-21085)
* 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
-rw-r--r--Include/internal/pycore_interp.h2
-rw-r--r--Include/internal/pycore_pylifecycle.h1
-rw-r--r--Lib/test/test_marshal.py7
-rw-r--r--Lib/test/test_set.py9
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst3
-rw-r--r--Misc/NEWS.d/next/Core and Builtins/2020-06-23-07-35-11.bpo-40521.dMNA6k.rst1
-rw-r--r--Objects/setobject.c38
-rw-r--r--Python/pylifecycle.c1
8 files changed, 8 insertions, 54 deletions
diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h
index 64e891f..c22bea7 100644
--- a/Include/internal/pycore_interp.h
+++ b/Include/internal/pycore_interp.h
@@ -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;
diff --git a/Include/internal/pycore_pylifecycle.h b/Include/internal/pycore_pylifecycle.h
index 9a3063a..30ba484 100644
--- a/Include/internal/pycore_pylifecycle.h
+++ b/Include/internal/pycore_pylifecycle.h
@@ -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);
diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py
index ace1593..b7f4dbb 100644
--- a/Lib/test/test_marshal.py
+++ b/Lib/test/test_marshal.py
@@ -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):
diff --git a/Lib/test/test_set.py b/Lib/test/test_set.py
index 9851a99..68d4942 100644
--- a/Lib/test/test_set.py
+++ b/Lib/test/test_set.py
@@ -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)
diff --git a/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst b/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst
index 95fab36..a62383d 100644
--- a/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst
@@ -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
index 0000000..25f146e
--- /dev/null
+++ b/Misc/NEWS.d/next/Core and Builtins/2020-06-23-07-35-11.bpo-40521.dMNA6k.rst
@@ -0,0 +1 @@
+Empty frozensets are no longer singletons.
diff --git a/Objects/setobject.c b/Objects/setobject.c
index 69bfc7d..b271149 100644
--- a/Objects/setobject.c
+++ b/Objects/setobject.c
@@ -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)
{
diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c
index f077072..09945a8 100644
--- a/Python/pylifecycle.c
+++ b/Python/pylifecycle.c
@@ -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);