korkmaz
korkmaz

Reputation: 101

cost of len() and pep8 suggestion on sequence empty check

If the complexity of python len() is O(1), why does pep8 suggest to use if seq: instead of if len(seq) == 0:

https://wiki.python.org/moin/TimeComplexity
https://www.python.org/dev/peps/pep-0008/#programming-recommendations

Isn't len(seq) == 0 more readable?

Upvotes: 4

Views: 2084

Answers (3)

chepner
chepner

Reputation: 532023

For if len(seq) == 0, you have to parse that

  1. you are calling a function,
  2. you are checking if its return value is equal to something, and
  3. that "something" is 0.

For if seq, you only have to parse that seq is being evaluated in a Boolean context.

You might argue that you also have to know what type seq has so you know what it means to evaluate it in a Boolean context, but then you also have to do know the type for len(seq) as well, so that you what it means to compute its length. (For example, for a dict d, len(d) says nothing about the values in the dictionary, only how many keys it has.)

Upvotes: 0

Bakuriu
Bakuriu

Reputation: 102029

The fact the len is O(1) is only a convention. There may be sequences/collections where len is not O(1) at that point checking len(x) == 0 could take asymptotically more time.

The fact is: the question "is the size of this collection equal to k?" and "is the collection empty?" are fundamentally different problems. The first is answered by len(x) == k and the latter by bool(x) [i.e. is x truthy]. Hence if you want to check if the collection is empty you just use if collection. They just happen to coincide if k == 0.

Generally you should use the most specific term to describe exactly what you are doing. Writing len(x) == 0 may just be a typo for len(x) == 10 with a missing 1 while getting if x wrong is harder.

Upvotes: 5

Cory Kramer
Cory Kramer

Reputation: 117981

The former can handle both empty string and None. For example consider these two variables.

>>> s1 = ''
>>> s2 = None

Using the first method

def test(s):
    if s:
        return True
    else:
        return False

>>> test(s1)
False
>>> test(s2)
False

Now using len

def test(s):
    if len(s) == 0:
        return True
    else:
        return False

>>> test(s1)
True
>>> test(s2)
Traceback (most recent call last):
  File "<pyshell#13>", line 1, in <module>
    test(s2)
  File "<pyshell#11>", line 2, in test
    if len(s) == 0:
TypeError: object of type 'NoneType' has no len()

So in terms of performance, both will be O(1), but the truthiness test (the first method) is more robust in that it handles None in addition to empty strings.

Upvotes: 8

Related Questions