frozenset() without arguments should return a singleton

S

Stefan Behnel

Hi!

frozenset() doesn't behave as the other immutable empty data types in 2.4:

..>>> '' is ''
True
..>>> () is ()
True
..>>> frozenset() is frozenset()
False

..>>> id(()),id(())
(1077579820, 1077579820)
..>>> id(())
1077579820
..>>> id(frozenset()),id(frozenset())
(1077581296, 1077581296)
..>>> id(frozenset())
1077581440
..>>> id(frozenset(()))
1077582256

frozenset() called without arguments (or on empty sequences) should always
return a singleton object. It is immutable, so I can't see a reason why it
should take up more resources than necessary.

Stefan
 
T

Terry Reedy

Stefan Behnel said:
Hi!

frozenset() doesn't behave as the other immutable empty data types in
2.4:

.>>> '' is ''
True
.>>> () is ()
True

I believe the reference manual describes this sort of behavior for
immutables as an *optional* optimization. 0 is 0 and has been since at
least 1.3. I am not sure both of your statements above have been true as
long, but I not longer have 1.3 to check ;-).
.>>> frozenset() is frozenset()
False
frozenset() called without arguments (or on empty sequences)
should always return a singleton object.

If we interpret 'should' as 'preferably by me', ok.
It is immutable, so I can't see a reason why it should take up more
resources than necessary.

It will take some programmer's time to add the special case check and run
the test suite, and check in the changes. Yours? And perhaps some
execution time for each frozenset call. Since frozenset is not much used,
and multiple empty frozensets very rare, and the difference mostly
invisible, the frozenset implementor probably went on to other things.

Terry J. Reedy
 
S

Stefan Behnel

Terry said:
If we interpret 'should' as 'preferably by me', ok.

It will take some programmer's time to add the special case check and run
the test suite, and check in the changes. Yours? And perhaps some
execution time for each frozenset call. Since frozenset is not much used,
and multiple empty frozensets very rare, and the difference mostly
invisible, the frozenset implementor probably went on to other things.

I read 'not much used' and 'very rare' as 'I rarely use them'. Others may.

It does not take much additional execution time, I just checked, a partial
test is already in there that should be enough for the 'frozenset()' case.
Additional tests for empty iterables would however be more costly and
therefore not necessarily worth doing. Up to the maintainers.

I don't have any experience in writing extension modules for the standard
library and 'running the test suite'. Implementing the check is trivial,
though. Could anyone please 'run the test suite' ?

I tested it a bit, though, seems to work, including subclassing.

Stefan

--- Objects/setobject.c.ORIG 2005-02-12 14:04:54.000000000 +0100
+++ Objects/setobject.c 2005-02-12 14:41:04.000000000 +0100
@@ -76,6 +76,8 @@
return (PyObject *)so;
}

+PyObject *frozen_empty_set = NULL;
+
static PyObject *
frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
@@ -83,7 +85,14 @@

if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable))
return NULL;
- if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) {
+ if (iterable == NULL) {
+ if (type == &PyFrozenSet_Type) {
+ if (frozen_empty_set == NULL)
+ frozen_empty_set = make_new_set(type, NULL);
+ Py_INCREF(frozen_empty_set);
+ return frozen_empty_set;
+ }
+ } else if (PyFrozenSet_CheckExact(iterable)) {
Py_INCREF(iterable);
return iterable;
}

--- Objects/setobject.c.ORIG 2005-02-12 14:04:54.000000000 +0100
+++ Objects/setobject.c 2005-02-12 14:41:04.000000000 +0100
@@ -76,6 +76,8 @@
return (PyObject *)so;
}

+PyObject *frozen_empty_set = NULL;
+
static PyObject *
frozenset_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
{
@@ -83,7 +85,14 @@

if (!PyArg_UnpackTuple(args, type->tp_name, 0, 1, &iterable))
return NULL;
- if (iterable != NULL && PyFrozenSet_CheckExact(iterable)) {
+ if (iterable == NULL) {
+ if (type == &PyFrozenSet_Type) {
+ if (frozen_empty_set == NULL)
+ frozen_empty_set = make_new_set(type, NULL);
+ Py_INCREF(frozen_empty_set);
+ return frozen_empty_set;
+ }
+ } else if (PyFrozenSet_CheckExact(iterable)) {
Py_INCREF(iterable);
return iterable;
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top