frozenset() without arguments should return a singleton

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Stefan Behnel

    #1

    frozenset() without arguments should return a singleton

    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
  • Terry Reedy

    #2
    Re: frozenset() without arguments should return a singleton


    "Stefan Behnel" <stefan.behne l-n05pAM@web.de> wrote in message
    news:cuj06r$ep5 $1@lnx107.hrz.t u-darmstadt.de...[color=blue]
    > Hi!
    >
    > frozenset() doesn't behave as the other immutable empty data types in
    > 2.4:
    >
    > .>>> '' is ''
    > True
    > .>>> () is ()
    > True[/color]

    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 ;-).
    [color=blue]
    > .>>> frozenset() is frozenset()
    > False[/color]
    [color=blue]
    > frozenset() called without arguments (or on empty sequences)
    > should always return a singleton object.[/color]

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

    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




    Comment

    • Stefan Behnel

      #3
      [PATCH] Re: frozenset() without arguments should return a singleton


      Terry Reedy schrieb:[color=blue][color=green]
      >>frozenset() called without arguments (or on empty sequences)
      >>should always return a singleton object.[/color]
      >
      > 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.[/color]

      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.ORI G 2005-02-12 14:04:54.000000 000 +0100
      +++ Objects/setobject.c 2005-02-12 14:41:04.000000 000 +0100
      @@ -76,6 +76,8 @@
      return (PyObject *)so;
      }

      +PyObject *frozen_empty_s et = NULL;
      +
      static PyObject *
      frozenset_new(P yTypeObject *type, PyObject *args, PyObject *kwds)
      {
      @@ -83,7 +85,14 @@

      if (!PyArg_UnpackT uple(args, type->tp_name, 0, 1, &iterable))
      return NULL;
      - if (iterable != NULL && PyFrozenSet_Che ckExact(iterabl e)) {
      + if (iterable == NULL) {
      + if (type == &PyFrozenSet_Ty pe) {
      + if (frozen_empty_s et == NULL)
      + frozen_empty_se t = make_new_set(ty pe, NULL);
      + Py_INCREF(froze n_empty_set);
      + return frozen_empty_se t;
      + }
      + } else if (PyFrozenSet_Ch eckExact(iterab le)) {
      Py_INCREF(itera ble);
      return iterable;
      }

      --- Objects/setobject.c.ORI G 2005-02-12 14:04:54.000000 000 +0100
      +++ Objects/setobject.c 2005-02-12 14:41:04.000000 000 +0100
      @@ -76,6 +76,8 @@
      return (PyObject *)so;
      }

      +PyObject *frozen_empty_s et = NULL;
      +
      static PyObject *
      frozenset_new(P yTypeObject *type, PyObject *args, PyObject *kwds)
      {
      @@ -83,7 +85,14 @@

      if (!PyArg_UnpackT uple(args, type->tp_name, 0, 1, &iterable))
      return NULL;
      - if (iterable != NULL && PyFrozenSet_Che ckExact(iterabl e)) {
      + if (iterable == NULL) {
      + if (type == &PyFrozenSet_Ty pe) {
      + if (frozen_empty_s et == NULL)
      + frozen_empty_se t = make_new_set(ty pe, NULL);
      + Py_INCREF(froze n_empty_set);
      + return frozen_empty_se t;
      + }
      + } else if (PyFrozenSet_Ch eckExact(iterab le)) {
      Py_INCREF(itera ble);
      return iterable;
      }

      Comment

      Working...