78 lines
2.9 KiB
Plaintext
78 lines
2.9 KiB
Plaintext
Identity operators ``++is++`` and ``++is not++`` check if the same object is on both sides, i.e. ``++a is b++`` returns ``++True++`` if ``++id(a) == id(b)++``.
|
|
|
|
|
|
Integers, bytes, floats, strings, frozensets and tuples should not be compared with identity operators because the result may not be as expected. If you need to compare these types you should use instead equality operators ``++==++`` or ``++!=++``.
|
|
|
|
|
|
The CPython interpreter caches certain builtin values for integers, bytes, floats, strings, frozensets and tuples. For example, the literal ``++1++`` will create the same object as ``++int("1")++``, which means that ``++1 is int("1")++`` is True. However this works only by chance as other integer values are not cached, for example ``++int("1000") is 1000++`` will always be ``++False++``. This behavior is not part of Python language specification and could vary between interpreters. CPython 3.8 even https://docs.python.org/3.8/whatsnew/3.8.html#changes-in-python-behavior[warns about comparing literals using identity operators].
|
|
|
|
|
|
The only case where using the "is" operator with a cached type is ok is with "interned" strings. Note however that interned strings don't necessarily have the same identity as string literals.
|
|
|
|
|
|
This rule raises an issue when at least one operand of an identity operator:
|
|
|
|
* is of type ``++int++``, ``++bytes++``, ``++float++``, ``++frozenset++`` or ``++tuple++``.
|
|
* or it is a string literal.
|
|
|
|
|
|
== Noncompliant Code Example
|
|
|
|
[source,python]
|
|
----
|
|
def literal_comparison(param):
|
|
param is 2000 # Noncompliant
|
|
|
|
literal_comparison(2000) # will return True
|
|
literal_comparison(int("2000")) # will return False
|
|
|
|
() is tuple() # Noncompliant. Always True
|
|
(1,) is tuple([1]) # Noncompliant. Always False
|
|
|
|
from sys import intern
|
|
|
|
with open("test.txt") as f: # test.txt contains "blabla\n"
|
|
text = f.read()
|
|
intern(text) is "blabla\n" # Noncompliant. Always False
|
|
----
|
|
|
|
|
|
== Compliant Solution
|
|
|
|
[source,python]
|
|
----
|
|
def literal_comparison(param):
|
|
param == 2000
|
|
|
|
literal_comparison(2000) # will return True
|
|
literal_comparison(int("2000")) # will return True
|
|
|
|
() == tuple() # Always True
|
|
(1,) == tuple([1]) # Always True
|
|
|
|
from sys import intern
|
|
|
|
with open("tmp/test.txt") as f: # test.txt contains "blabla\n"
|
|
text = f.read()
|
|
intern(text) is intern("blabla\n") # Always True
|
|
----
|
|
|
|
|
|
== See
|
|
|
|
* https://adamj.eu/tech/2020/01/21/why-does-python-3-8-syntaxwarning-for-is-literal/[Why does Python 3.8 log a SyntaxWarning for 'is' with literals?] - Adam Johnson
|
|
* https://treyhunner.com/2019/03/unique-and-sentinel-values-in-python/#Equality_vs_identity[Equality vs identity] - Trey Hunner
|
|
* https://docs.python.org/3.7/library/sys.html?highlight=sys.intern#sys.intern[Python documentation - sys.intern]
|
|
|
|
ifdef::env-github,rspecator-view[]
|
|
|
|
'''
|
|
== Implementation Specification
|
|
(visible only on this page)
|
|
|
|
include::message.adoc[]
|
|
|
|
include::highlighting.adoc[]
|
|
|
|
endif::env-github,rspecator-view[]
|