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 261cfedf76
.
* bpo-40521: Empty frozensets are no longer singletons
* Complete the removal of the frozenset singleton
This commit is contained in:
parent
522691c46e
commit
f9bd05e83e
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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):
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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.
|
||||
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
Empty frozensets are no longer singletons.
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue