Skip to content

Commit 0ecf8ec

Browse files
committed
gh-150165: Clarify membership test semantics for hash-based containers and object identity
Split the membership test equivalence in §6.10.2 to distinguish sequence types (linear scan) from hash-based containers (hash lookup). Add a note acknowledging that the x is e check has observable consequences for NaN and state-dependent __eq__, and that object identity is unspecified for non-literal expressions. Also add a clarifying sentence in §6.2.3.1 noting that non-literal expressions make no identity guarantees.
1 parent 87a879f commit 0ecf8ec

1 file changed

Lines changed: 19 additions & 3 deletions

File tree

Doc/reference/expressions.rst

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,9 @@ both their structure and the *identity* of the values match.
256256
Currently, each evaluation of a template string results in
257257
a different object.
258258

259+
Other expressions which are not literals (such as calls,
260+
comprehensions, and attribute accesses) likewise make no guarantees
261+
about object identity across separate evaluations.
259262

260263
.. _string-concatenation:
261264

@@ -1977,9 +1980,22 @@ The operators :keyword:`in` and :keyword:`not in` test for membership. ``x in
19771980
s`` evaluates to ``True`` if *x* is a member of *s*, and ``False`` otherwise.
19781981
``x not in s`` returns the negation of ``x in s``. All built-in sequences and
19791982
set types support this as well as dictionary, for which :keyword:`!in` tests
1980-
whether the dictionary has a given key. For container types such as list, tuple,
1981-
set, frozenset, dict, or collections.deque, the expression ``x in y`` is equivalent
1982-
to ``any(x is e or x == e for e in y)``.
1983+
whether the dictionary has a given key. For sequence types such as list, tuple, or collections.deque,
1984+
the expression ``x in y`` is equivalent to ``any(x is e or x == e for e in y)``.
1985+
1986+
For hash-based container types such as set, frozenset, and dict,
1987+
``x in y`` first hashes *x* to locate a candidate element *e*, then
1988+
returns ``True`` if ``x is e or x == e``. This is equivalent to the
1989+
sequence case under the assumption that equal objects have the same
1990+
hash value.
1991+
1992+
.. note::
1993+
1994+
The ``x is e`` check means that for objects where ``x != x``
1995+
(such as NaN) or where ``__eq__`` is state-dependent, membership
1996+
can succeed via identity even when equality fails. This behavior
1997+
is not guaranteed across implementations, as object identity for
1998+
repeated evaluations of non-literal expressions is unspecified.
19831999

19842000
For the string and bytes types, ``x in y`` is ``True`` if and only if *x* is a
19852001
substring of *y*. An equivalent test is ``y.find(x) != -1``. Empty strings are

0 commit comments

Comments
 (0)