rspec/rules/S5796/python/rule.adoc

95 lines
2.7 KiB
Plaintext
Raw Normal View History

2023-06-30 10:36:32 +02:00
This rule raises an issue when at least one operand of an identity operator is a new object which has been created just for this check.
== Why is this an issue?
2021-04-28 16:49:39 +02:00
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)++``.
2023-06-30 10:36:32 +02:00
When a new object is created, it will have its own identity. Thus, if an object is created and used only in an identity check, it is not possible for the other operand to be the same object. The comparison is always ``++False++`` or always ``++True++`` depending on the operator used, ``++is++`` or ``++is not++``.
2021-04-28 16:49:39 +02:00
This rule raises an issue when at least one operand of an identity operator is a new object which has been created just for this check, i.e.:
* When it is a dict, list or set literal.
* When it is a call to ``++dict++``, ``++set++``, ``++list++`` or ``++complex++`` built-in functions.
* When such a new object is assigned to only one variable and this variable is used in an identity check.
2023-06-30 10:36:32 +02:00
== How to fix it
Whenever using a newly created object in a comparison, the identity operator should be replaced with the equality operator (`==` or `!=`), which will use ``++__eq__++`` or ``++__ne__++`` methods under the hood.
2023-06-30 10:36:32 +02:00
=== Code examples
==== Noncompliant code example
2021-04-28 16:49:39 +02:00
2022-02-04 17:28:24 +01:00
[source,python]
2021-04-28 16:49:39 +02:00
----
def func(param):
2023-06-30 10:36:32 +02:00
param is {1: 2} # Noncompliant: always False
param is not {1, 2, 3} # Noncompliant: always True
param is [1, 2, 3] # Noncompliant: always False
2021-04-28 16:49:39 +02:00
2023-06-30 10:36:32 +02:00
param is dict(a=1) # Noncompliant: always False
2021-04-28 16:49:39 +02:00
mylist = [] # mylist is assigned a new object
2023-06-30 10:36:32 +02:00
param is mylist # Noncompliant: always False
2021-04-28 16:49:39 +02:00
----
2023-06-30 10:36:32 +02:00
==== Compliant solution
2021-04-28 16:49:39 +02:00
2022-02-04 17:28:24 +01:00
[source,python]
2021-04-28 16:49:39 +02:00
----
def func(param):
param == {1: 2}
param != {1, 2, 3}
param == [1, 2, 3]
param == dict(a=1)
mylist = []
param == mylist
----
== Resources
2021-04-28 16:49:39 +02:00
2023-06-30 10:36:32 +02:00
=== Articles & blog posts
2021-04-28 16:49:39 +02:00
* 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
ifdef::env-github,rspecator-view[]
'''
== Implementation Specification
(visible only on this page)
=== Message
* Replace this "is" operator with "==".
* Replace this "is not" operator with "!=".
=== Highlighting
Primary: the "is" or "is not" operator.
Secondar(y|ies):
If the new object is passed via a variable
* location1: the assigned value
* message1: "This expression creates a new object every time."
'''
== Comments And Links
(visible only on this page)
=== is related to: S5914
endif::env-github,rspecator-view[]