From 00c029a6c22c7caadb17c6277b6f9c561210c51f Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 23 Jun 2020 06:14:29 -0700 Subject: [PATCH 1/3] Revert "bpo-40521: Make the empty frozenset per interpreter (GH-21068)" This reverts commit 261cfedf7657a515e04428bba58eba2a9bb88208. --- Include/internal/pycore_interp.h | 2 -- Include/internal/pycore_pylifecycle.h | 1 - .../2020-05-20-01-17-34.bpo-40521.wvAehI.rst | 3 ++- Objects/setobject.c | 27 ++++++------------- Python/pylifecycle.c | 4 ++- 5 files changed, 13 insertions(+), 24 deletions(-) diff --git a/Include/internal/pycore_interp.h b/Include/internal/pycore_interp.h index 64e891f9f6eb4d..c22bea75d2795c 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 9a3063aa2775f0..30ba48423f9ec4 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/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 95fab369748f0a..a62383d2093ecd 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/Objects/setobject.c b/Objects/setobject.c index 69bfc7d0a58fb2..e6baaf8a5b4570 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -975,11 +975,12 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable) return make_new_set(type, iterable); } +/* The empty frozenset is a singleton */ +static PyObject *emptyfrozenset = NULL; + static PyObject * make_new_frozenset(PyTypeObject *type, PyObject *iterable) { - PyObject *res; - if (type != &PyFrozenSet_Type) { return make_new_set(type, iterable); } @@ -990,7 +991,7 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable) Py_INCREF(iterable); return iterable; } - res = make_new_set((PyTypeObject *)type, iterable); + PyObject *res = make_new_set((PyTypeObject *)type, iterable); if (res == NULL || PySet_GET_SIZE(res) != 0) { return res; } @@ -999,17 +1000,11 @@ make_new_frozenset(PyTypeObject *type, PyObject *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; - } + if (emptyfrozenset == NULL) { + emptyfrozenset = make_new_set((PyTypeObject *)type, NULL); } - Py_INCREF(res); - return res; + Py_XINCREF(emptyfrozenset); + return emptyfrozenset; } static PyObject * @@ -2304,12 +2299,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 f0770727f4de71..5a6dbc9418bd7c 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1253,7 +1253,9 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp) _PyAsyncGen_Fini(tstate); _PyContext_Fini(tstate); - _PySet_Fini(tstate); + if (is_main_interp) { + _PySet_Fini(); + } _PyDict_Fini(tstate); _PyList_Fini(tstate); _PyTuple_Fini(tstate); From da8e997a082ffea1c0109d2b0d850ae23da77d32 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 23 Jun 2020 07:35:51 -0700 Subject: [PATCH 2/3] bpo-40521: Empty frozensets are no longer singletons --- Lib/test/test_marshal.py | 7 ----- Lib/test/test_set.py | 9 ------- .../2020-06-23-07-35-11.bpo-40521.dMNA6k.rst | 1 + Objects/setobject.c | 27 ++++--------------- 4 files changed, 6 insertions(+), 38 deletions(-) create mode 100644 Misc/NEWS.d/next/Core and Builtins/2020-06-23-07-35-11.bpo-40521.dMNA6k.rst diff --git a/Lib/test/test_marshal.py b/Lib/test/test_marshal.py index ace1593999d4eb..b7f4dbb98e36d4 100644 --- a/Lib/test/test_marshal.py +++ b/Lib/test/test_marshal.py @@ -158,13 +158,6 @@ def test_sets(self): 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 9851a998983f83..68d494213e5870 100644 --- a/Lib/test/test_set.py +++ b/Lib/test/test_set.py @@ -661,15 +661,6 @@ def test_init(self): 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-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 00000000000000..25f146e35ef439 --- /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 e6baaf8a5b4570..924b1cf1333364 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -975,9 +975,6 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable) return make_new_set(type, iterable); } -/* The empty frozenset is a singleton */ -static PyObject *emptyfrozenset = NULL; - static PyObject * make_new_frozenset(PyTypeObject *type, PyObject *iterable) { @@ -985,26 +982,12 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable) return make_new_set(type, iterable); } - if (iterable != NULL) { - if (PyFrozenSet_CheckExact(iterable)) { - /* frozenset(f) is idempotent */ - Py_INCREF(iterable); - return iterable; - } - PyObject *res = make_new_set((PyTypeObject *)type, iterable); - if (res == NULL || PySet_GET_SIZE(res) != 0) { - return res; + if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) { + /* frozenset(f) is idempotent */ + Py_INCREF(iterable); + return iterable; } - /* If the created frozenset is empty, return the empty frozenset singleton instead */ - Py_DECREF(res); - } - - // The empty frozenset is a singleton - if (emptyfrozenset == NULL) { - emptyfrozenset = make_new_set((PyTypeObject *)type, NULL); - } - Py_XINCREF(emptyfrozenset); - return emptyfrozenset; + return make_new_set((PyTypeObject *)type, iterable); } static PyObject * From a29440ccdaaacaa9619c2141367ef07e93610885 Mon Sep 17 00:00:00 2001 From: Raymond Hettinger Date: Tue, 23 Jun 2020 07:57:49 -0700 Subject: [PATCH 3/3] Complete the removal of the frozenset singleton --- Objects/setobject.c | 2 +- Python/pylifecycle.c | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/Objects/setobject.c b/Objects/setobject.c index 924b1cf1333364..b2711495b657bd 100644 --- a/Objects/setobject.c +++ b/Objects/setobject.c @@ -986,7 +986,7 @@ make_new_frozenset(PyTypeObject *type, PyObject *iterable) /* frozenset(f) is idempotent */ Py_INCREF(iterable); return iterable; - } + } return make_new_set((PyTypeObject *)type, iterable); } diff --git a/Python/pylifecycle.c b/Python/pylifecycle.c index 5a6dbc9418bd7c..09945a8f7a6a07 100644 --- a/Python/pylifecycle.c +++ b/Python/pylifecycle.c @@ -1253,9 +1253,6 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp) _PyAsyncGen_Fini(tstate); _PyContext_Fini(tstate); - if (is_main_interp) { - _PySet_Fini(); - } _PyDict_Fini(tstate); _PyList_Fini(tstate); _PyTuple_Fini(tstate); pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy