bpo-43325: Add FAQ entry for identity tests (GH-25168)

This commit is contained in:
Raymond Hettinger 2021-04-03 19:54:49 -07:00 committed by GitHub
parent 35715d1e72
commit f8775e4f72
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 89 additions and 3 deletions

View file

@ -1701,6 +1701,93 @@ to the object:
13891296
When can I rely on identity tests with the *is* operator?
---------------------------------------------------------
The ``is`` operator tests for object identity. The test ``a is b`` is
equivalent to ``id(a) == id(b)``.
The most important property of an identity test is that an object is always
identical to itself, ``a is a`` always returns ``True``. Identity tests are
usually faster than equality tests. And unlike equality tests, identity tests
are guaranteed to return a boolean ``True`` or ``False``.
However, identity tests can *only* be substituted for equality tests when
object identity is assured. Generally, there are three circumstances where
identity is guaranteed:
1) Assignments create new names but do not change object identity. After the
assignment ``new = old``, it is guaranteed that ``new is old``.
2) Putting an object in a container that stores object references does not
change object identity. After the list assignment ``s[0] = x``, it is
guaranteed that ``s[0] is x``.
3) If an object is a singleton, it means that only one instance of that object
can exist. After the assignments ``a = None`` and ``b = None``, it is
guaranteed that ``a is b`` because ``None`` is a singleton.
In most other circumstances, identity tests are inadvisable and equality tests
are preferred. In particular, identity tests should not be used to check
constants such as :class:`int` and :class:`str` which aren't guaranteed to be
singletons::
>>> a = 1000
>>> b = 500
>>> c = b + 500
>>> a is c
False
>>> a = 'Python'
>>> b = 'Py'
>>> c = b + 'thon'
>>> a is c
False
Likewise, new instances of mutable containers are never identical::
>>> a = []
>>> b = []
>>> a is b
False
In the standard library code, you will see several common patterns for
correctly using identity tests:
1) As recommended by :pep:`8`, an identity test is the preferred way to check
for ``None``. This reads like plain English in code and avoids confusion with
other objects that may have boolean values that evaluate to false.
2) Detecting optional arguments can be tricky when ``None`` is a valid input
value. In those situations, you can create an singleton sentinel object
guaranteed to be distinct from other objects. For example, here is how
to implement a method that behaves like :meth:`dict.pop`::
_sentinel = object()
def pop(self, key, default=_sentinel):
if key in self:
value = self[key]
del self[key]
return value
if default is _sentinel:
raise KeyError(key)
return default
3) Container implementations sometimes need to augment equality tests with
identity tests. This prevents the code from being confused by objects such as
``float('NaN')`` that are not equal to themselves.
For example, here is the implementation of
:meth:`collections.abc.Sequence.__contains__`::
def __contains__(self, value):
for v in self:
if v is value or v == value:
return True
return False
Modules
=======

View file

@ -661,9 +661,8 @@ operators, not just comparisons.
The comparison operators ``in`` and ``not in`` check whether a value occurs
(does not occur) in a sequence. The operators ``is`` and ``is not`` compare
whether two objects are really the same object; this only matters for mutable
objects like lists. All comparison operators have the same priority, which is
lower than that of all numerical operators.
whether two objects are really the same object. All comparison operators have
the same priority, which is lower than that of all numerical operators.
Comparisons can be chained. For example, ``a < b == c`` tests whether ``a`` is
less than ``b`` and moreover ``b`` equals ``c``.