Skip to content

Commit f9bd05e

Browse files
authored
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 261cfed. * bpo-40521: Empty frozensets are no longer singletons * Complete the removal of the frozenset singleton
1 parent 522691c commit f9bd05e

File tree

8 files changed

+8
-54
lines changed

8 files changed

+8
-54
lines changed

Include/internal/pycore_interp.h

-2
Original file line numberDiff line numberDiff line change
@@ -244,8 +244,6 @@ struct _is {
244244
/* Using a cache is very effective since typically only a single slice is
245245
created and then deleted again. */
246246
PySliceObject *slice_cache;
247-
// The empty frozenset is a singleton.
248-
PyObject *empty_frozenset;
249247

250248
struct _Py_tuple_state tuple;
251249
struct _Py_list_state list;

Include/internal/pycore_pylifecycle.h

-1
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,6 @@ extern void _PyFrame_Fini(PyThreadState *tstate);
6262
extern void _PyDict_Fini(PyThreadState *tstate);
6363
extern void _PyTuple_Fini(PyThreadState *tstate);
6464
extern void _PyList_Fini(PyThreadState *tstate);
65-
extern void _PySet_Fini(PyThreadState *tstate);
6665
extern void _PyBytes_Fini(PyThreadState *tstate);
6766
extern void _PyFloat_Fini(PyThreadState *tstate);
6867
extern void _PySlice_Fini(PyThreadState *tstate);

Lib/test/test_marshal.py

-7
Original file line numberDiff line numberDiff line change
@@ -158,13 +158,6 @@ def test_sets(self):
158158
for constructor in (set, frozenset):
159159
self.helper(constructor(self.d.keys()))
160160

161-
@support.cpython_only
162-
def test_empty_frozenset_singleton(self):
163-
# marshal.loads() must reuse the empty frozenset singleton
164-
obj = frozenset()
165-
obj2 = marshal.loads(marshal.dumps(obj))
166-
self.assertIs(obj2, obj)
167-
168161

169162
class BufferTestCase(unittest.TestCase, HelperMixin):
170163

Lib/test/test_set.py

-9
Original file line numberDiff line numberDiff line change
@@ -661,15 +661,6 @@ def test_init(self):
661661
s.__init__(self.otherword)
662662
self.assertEqual(s, set(self.word))
663663

664-
def test_singleton_empty_frozenset(self):
665-
f = frozenset()
666-
efs = [frozenset(), frozenset([]), frozenset(()), frozenset(''),
667-
frozenset(), frozenset([]), frozenset(()), frozenset(''),
668-
frozenset(range(0)), frozenset(frozenset()),
669-
frozenset(f), f]
670-
# All of the empty frozensets should have just one id()
671-
self.assertEqual(len(set(map(id, efs))), 1)
672-
673664
def test_constructor_identity(self):
674665
s = self.thetype(range(3))
675666
t = self.thetype(s)

Misc/NEWS.d/next/Core and Builtins/2020-05-20-01-17-34.bpo-40521.wvAehI.rst

+2-1
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,9 @@ Each interpreter now its has own free lists, singletons and caches:
22

33
* Free lists: float, tuple, list, dict, frame, context,
44
asynchronous generator.
5-
* Singletons: empty tuple, empty frozenset, empty bytes string,
5+
* Singletons: empty tuple, empty bytes string,
66
single byte character.
77
* Slice cache.
88

99
They are no longer shared by all interpreters.
10+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Empty frozensets are no longer singletons.

Objects/setobject.c

+5-33
Original file line numberDiff line numberDiff line change
@@ -978,38 +978,16 @@ make_new_set_basetype(PyTypeObject *type, PyObject *iterable)
978978
static PyObject *
979979
make_new_frozenset(PyTypeObject *type, PyObject *iterable)
980980
{
981-
PyObject *res;
982-
983981
if (type != &PyFrozenSet_Type) {
984982
return make_new_set(type, iterable);
985983
}
986984

987-
if (iterable != NULL) {
988-
if (PyFrozenSet_CheckExact(iterable)) {
989-
/* frozenset(f) is idempotent */
990-
Py_INCREF(iterable);
991-
return iterable;
992-
}
993-
res = make_new_set((PyTypeObject *)type, iterable);
994-
if (res == NULL || PySet_GET_SIZE(res) != 0) {
995-
return res;
996-
}
997-
/* If the created frozenset is empty, return the empty frozenset singleton instead */
998-
Py_DECREF(res);
985+
if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) {
986+
/* frozenset(f) is idempotent */
987+
Py_INCREF(iterable);
988+
return iterable;
999989
}
1000-
1001-
// The empty frozenset is a singleton
1002-
PyInterpreterState *interp = _PyInterpreterState_GET();
1003-
res = interp->empty_frozenset;
1004-
if (res == NULL) {
1005-
interp->empty_frozenset = make_new_set((PyTypeObject *)type, NULL);
1006-
res = interp->empty_frozenset;
1007-
if (res == NULL) {
1008-
return NULL;
1009-
}
1010-
}
1011-
Py_INCREF(res);
1012-
return res;
990+
return make_new_set((PyTypeObject *)type, iterable);
1013991
}
1014992

1015993
static PyObject *
@@ -2304,12 +2282,6 @@ PySet_Add(PyObject *anyset, PyObject *key)
23042282
return set_add_key((PySetObject *)anyset, key);
23052283
}
23062284

2307-
void
2308-
_PySet_Fini(PyThreadState *tstate)
2309-
{
2310-
Py_CLEAR(tstate->interp->empty_frozenset);
2311-
}
2312-
23132285
int
23142286
_PySet_NextEntry(PyObject *set, Py_ssize_t *pos, PyObject **key, Py_hash_t *hash)
23152287
{

Python/pylifecycle.c

-1
Original file line numberDiff line numberDiff line change
@@ -1253,7 +1253,6 @@ finalize_interp_types(PyThreadState *tstate, int is_main_interp)
12531253
_PyAsyncGen_Fini(tstate);
12541254
_PyContext_Fini(tstate);
12551255

1256-
_PySet_Fini(tstate);
12571256
_PyDict_Fini(tstate);
12581257
_PyList_Fini(tstate);
12591258
_PyTuple_Fini(tstate);

0 commit comments

Comments
 (0)