45

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:

enter image description here

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?

renatov
  • 5,005
  • 6
  • 31
  • 38
  • Related: http://stackoverflow.com/questions/1504717/why-does-comparing-strings-in-python-using-either-or-is-sometimes-produce – Andy May 10 '15 at 03:34
  • 3
    The `==` isn't *wrong*, it's just suggesting that there's a better way to do it. – Mark Ransom May 10 '15 at 03:44
  • Using the `==` operator seems more explicit, but it would force type differenciation. Since Python is "duck typed", I guess that's why they came with a single solution to check if a sequence is empty. Using `if seq:` works for lists, strings, tuples and dictionaries. – renatov May 10 '15 at 04:04
  • If anyone finds it useful, I created a youtube tutorial discussing the '==' operator and comparing the different ways to check if list is empty https://www.youtube.com/watch?v=8V88bl3tuBQ – Brendan Metcalfe Jun 27 '20 at 23:06

2 Answers2

33

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.

thefourtheye
  • 233,700
  • 52
  • 457
  • 497
  • But this doesn't seem the "pythonic" way of coding. Explicit comparing with an empty list seems more readable to me. Is it wrong? – renatov May 10 '15 at 03:35
  • 2
    @renatov: I suspect that Guido, Tim, and Barry have a better sense of what's pythonic than you do, but if you disagree, feel free to try to convince the Python community that PEP 8 needs to be changed. – abarnert May 10 '15 at 03:37
  • @abarnert the argument would carry more weight if the example showed exactly what the question asked, which to me is the most straight-forward and natural way to check for an empty list, more so than checking the length. – Mark Ransom May 10 '15 at 03:48
  • @MarkRansom: I think it's pretty clear that the intention is not "`if not seq:` is still bad, but we listed it as "Yes" just to make the point that `if len(seq):` is really bad". But people have been confused by the fact that it doesn't mention `if seq != ''` before, and people probably will be confused again. Maybe PEP 8 should be improved to make the intention clearer. – abarnert May 10 '15 at 03:53
  • @renatov: More importantly, thefourtheye showed you that PEP 8 says that `if not seq:` is a Yes. That's the answer you asked for. If you're not arguing that PEP 8 is wrong, what _are_ you saying? Are you asking for the rationale behind that decision, or for pointers to where it's been discussed? If so, that's a perfectly good question (although not necessarily a good question for SO), but it's not your original question, so asking it as a followup in the comments is not the way to get the answer. – abarnert May 10 '15 at 03:57
1

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)
Sylwit
  • 1,497
  • 1
  • 11
  • 20