[pypy-commit] pypy default: Add id/is support to the empty frozenset, similar to the empty tuple
arigo
pypy.commits at gmail.com
Mon Jun 13 13:41:06 EDT 2016
Author: Armin Rigo <arigo at tunes.org>
Branch:
Changeset: r85139:b80452987110
Date: 2016-06-13 19:40 +0200
http://bitbucket.org/pypy/pypy/changeset/b80452987110/
Log: Add id/is support to the empty frozenset, similar to the empty tuple
diff --git a/pypy/doc/cpython_differences.rst b/pypy/doc/cpython_differences.rst
--- a/pypy/doc/cpython_differences.rst
+++ b/pypy/doc/cpython_differences.rst
@@ -321,6 +321,8 @@
- ``tuple`` (empty tuples only)
+ - ``frozenset`` (empty frozenset only)
+
This change requires some changes to ``id`` as well. ``id`` fulfills the
following condition: ``x is y <=> id(x) == id(y)``. Therefore ``id`` of the
above types will return a value that is computed from the argument, and can
@@ -329,12 +331,13 @@
Note that strings of length 2 or greater can be equal without being
identical. Similarly, ``x is (2,)`` is not necessarily true even if
``x`` contains a tuple and ``x == (2,)``. The uniqueness rules apply
-only to the particular cases described above. The ``str``, ``unicode``
-and ``tuple`` rules were added in PyPy 5.4; before that, a test like
-``if x is "?"`` or ``if x is ()`` could fail even if ``x`` was equal to
-``"?"`` or ``()``. The new behavior added in PyPy 5.4 is closer to
-CPython's, which caches precisely the empty string, unicode and tuple,
-and (sometimes!) the single-character strings and unicodes.
+only to the particular cases described above. The ``str``, ``unicode``,
+``tuple`` and ``frozenset`` rules were added in PyPy 5.4; before that, a
+test like ``if x is "?"`` or ``if x is ()`` could fail even if ``x`` was
+equal to ``"?"`` or ``()``. The new behavior added in PyPy 5.4 is
+closer to CPython's, which caches precisely the empty
+string/unicode/tuple/frozenset, and (sometimes!) the single-character
+strings and unicodes.
Note that for floats there "``is``" only one object per "bit pattern"
of the float. So ``float('nan') is float('nan')`` is true on PyPy,
diff --git a/pypy/objspace/std/setobject.py b/pypy/objspace/std/setobject.py
--- a/pypy/objspace/std/setobject.py
+++ b/pypy/objspace/std/setobject.py
@@ -6,6 +6,7 @@
from pypy.objspace.std.bytesobject import W_BytesObject
from pypy.objspace.std.intobject import W_IntObject
from pypy.objspace.std.unicodeobject import W_UnicodeObject
+from pypy.objspace.std.util import IDTAG_SPECIAL, IDTAG_SHIFT
from rpython.rlib.objectmodel import r_dict
from rpython.rlib.objectmodel import iterkeys_with_hash, contains_with_hash
@@ -575,6 +576,23 @@
class W_FrozensetObject(W_BaseSetObject):
hash = 0
+ def is_w(self, space, w_other):
+ if not isinstance(w_other, W_FrozensetObject):
+ return False
+ if self is w_other:
+ return True
+ if self.user_overridden_class or w_other.user_overridden_class:
+ return False
+ # empty frozensets are unique-ified
+ return 0 == w_other.length() == self.length()
+
+ def immutable_unique_id(self, space):
+ if self.user_overridden_class or self.length() > 0:
+ return None
+ # empty frozenset: base value 259
+ uid = (259 << IDTAG_SHIFT) | IDTAG_SPECIAL
+ return space.wrap(uid)
+
def _newobj(self, space, w_iterable):
"""Make a new frozenset by taking ownership of 'w_iterable'."""
if type(self) is W_FrozensetObject:
diff --git a/pypy/objspace/std/test/test_obj.py b/pypy/objspace/std/test/test_obj.py
--- a/pypy/objspace/std/test/test_obj.py
+++ b/pypy/objspace/std/test/test_obj.py
@@ -204,6 +204,14 @@
skip("cannot run this test as apptest")
assert id(()) == (258 << 4) | 11 # always
+ def test_id_of_frozensets(self):
+ x = frozenset([4])
+ assert id(x) != id(frozenset([4])) # no caching at all
+ if self.appdirect:
+ skip("cannot run this test as apptest")
+ assert id(frozenset()) == (259 << 4) | 11 # always
+ assert id(frozenset([])) == (259 << 4) | 11 # always
+
def test_identity_vs_id_primitives(self):
import sys
l = range(-10, 10, 2)
@@ -218,12 +226,14 @@
l.append(1 + i * 1j)
l.append(1 - i * 1j)
l.append((i,))
+ l.append(frozenset([i]))
l.append(-0.0)
l.append(None)
l.append(True)
l.append(False)
l.append(())
l.append(tuple([]))
+ l.append(frozenset())
for i, a in enumerate(l):
for b in l[i:]:
diff --git a/pypy/objspace/std/util.py b/pypy/objspace/std/util.py
--- a/pypy/objspace/std/util.py
+++ b/pypy/objspace/std/util.py
@@ -14,6 +14,7 @@
# 256: empty string
# 257: empty unicode
# 258: empty tuple
+ # 259: empty frozenset
CMP_OPS = dict(lt='<', le='<=', eq='==', ne='!=', gt='>', ge='>=')
BINARY_BITWISE_OPS = {'and': '&', 'lshift': '<<', 'or': '|', 'rshift': '>>',
More information about the pypy-commit
mailing list