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
=======