Is it wrong to use the "==" operator when comparing to an empty list?
Question:
PyCharm (4.0.6) complains when I do a comparison to an empty list using the ==
operator, but it doesn’t when I use the is
operator:
I guess this is something related to PEP 8, but the problem is that when I use the is
operator, as PyCharm suggests, I have a false negative. Here is a simple example in iPython shell to show that in this case the ==
operator seems more appropriate, since the is
operator returns a false negative:
In[2]: actions = []
In[3]: actions == []
Out[3]: True
In[4]: actions is []
Out[4]: False
Could someone please explain why PyCharm complains about the ==
operator when comparing to an empty lists? Am I doing something wrong according to PEP 8?
Answers:
Quoting PEP-8’s Programming Recommendations section,
For sequences, (strings, lists, tuples), use the fact that empty sequences are false.
Yes: if not seq:
if seq:
No: if len(seq)
if not len(seq)
Since empty sequences are Falsy in Python,
>>> bool([])
False
>>> bool(())
False
you can simply use if not
as mentioned in the PEP-8.
Note: You should never use is
to compare if two values are equal, because is
operator checks if two objects are one and the same, but ==
checks if two objects are equal.
I dug in to the source code to figure out what is happening. When we do a == []
,
>>> dis(compile('if a == []: pass', "string", "exec"))
1 0 LOAD_NAME 0 (a)
3 BUILD_LIST 0
6 COMPARE_OP 2 (==)
9 POP_JUMP_IF_FALSE 15
12 JUMP_FORWARD 0 (to 15)
>> 15 LOAD_CONST 0 (None)
18 RETURN_VALUE
we are constructing a new list and it would be a very costly operation, just for comparison. On the other hand
>>> dis(compile('if not a: pass', "string", "exec"))
1 0 LOAD_NAME 0 (a)
3 POP_JUMP_IF_TRUE 9
6 JUMP_FORWARD 0 (to 9)
>> 9 LOAD_CONST 0 (None)
12 RETURN_VALUE
we are trying to see if the current sequence could be Truthy. This internally checks if the length of the sequence is zero (which is just a simple lookup, as the length of the list is maintained in a variable). If the length is zero, then if not actions:
will be Truthy. Here we don’t construct a new list, but we are just checking the length implicitly, instead of explicitly doing
if len(actions) == 0:
So, I am guessing that Python Gurus are suggesting if not seq
because there could be performance advantage as well.
According to PEP8 doc you should use
For sequences, (strings, lists, tuples), use the fact that empty sequences are false.
Yes: if not seq:
if seq:
No: if len(seq)
if not len(seq)
PyCharm (4.0.6) complains when I do a comparison to an empty list using the ==
operator, but it doesn’t when I use the is
operator:
I guess this is something related to PEP 8, but the problem is that when I use the is
operator, as PyCharm suggests, I have a false negative. Here is a simple example in iPython shell to show that in this case the ==
operator seems more appropriate, since the is
operator returns a false negative:
In[2]: actions = []
In[3]: actions == []
Out[3]: True
In[4]: actions is []
Out[4]: False
Could someone please explain why PyCharm complains about the ==
operator when comparing to an empty lists? Am I doing something wrong according to PEP 8?
Quoting PEP-8’s Programming Recommendations section,
For sequences, (strings, lists, tuples), use the fact that empty sequences are false.
Yes: if not seq: if seq: No: if len(seq) if not len(seq)
Since empty sequences are Falsy in Python,
>>> bool([])
False
>>> bool(())
False
you can simply use if not
as mentioned in the PEP-8.
Note: You should never use is
to compare if two values are equal, because is
operator checks if two objects are one and the same, but ==
checks if two objects are equal.
I dug in to the source code to figure out what is happening. When we do a == []
,
>>> dis(compile('if a == []: pass', "string", "exec"))
1 0 LOAD_NAME 0 (a)
3 BUILD_LIST 0
6 COMPARE_OP 2 (==)
9 POP_JUMP_IF_FALSE 15
12 JUMP_FORWARD 0 (to 15)
>> 15 LOAD_CONST 0 (None)
18 RETURN_VALUE
we are constructing a new list and it would be a very costly operation, just for comparison. On the other hand
>>> dis(compile('if not a: pass', "string", "exec"))
1 0 LOAD_NAME 0 (a)
3 POP_JUMP_IF_TRUE 9
6 JUMP_FORWARD 0 (to 9)
>> 9 LOAD_CONST 0 (None)
12 RETURN_VALUE
we are trying to see if the current sequence could be Truthy. This internally checks if the length of the sequence is zero (which is just a simple lookup, as the length of the list is maintained in a variable). If the length is zero, then if not actions:
will be Truthy. Here we don’t construct a new list, but we are just checking the length implicitly, instead of explicitly doing
if len(actions) == 0:
So, I am guessing that Python Gurus are suggesting if not seq
because there could be performance advantage as well.
According to PEP8 doc you should use
For sequences, (strings, lists, tuples), use the fact that empty sequences are false.
Yes: if not seq:
if seq:
No: if len(seq)
if not len(seq)