See this Stack Overflow topic for details:
http://stackoverflow.com/questions/43121340/why-is-the-use-of-lensequence-in-condition-values-considered-incorrect-by-pyli
In short (and to make the issue self-sufficient), writing len(SEQUENCE) == 0 or similar expressions such aslen(SEQUENCE) > 0 as a condition value triggers C1801 with the message "Do not use len(SEQUENCE) as condition value", which can give a wrong (or at the very least, unclear) impression.
I created that question because I ended up wondering whether calling len on a collection or sequence had unexpected consequences in my code, while C1801 was actually attempting to warn me about the idiomatic form of checking for empty collections: if SEQ: and if not SEQ: do not trigger the warning, but nothing in the message advised me to write this.
This was apparently derived from PEP8, but note that PEP8 also says "a foolish consistency is the hobgoblin of small minds". It goes too far to claim that using len(..) == 0 as a condition is incorrect. There is a theoretical gain in efficiency, when len() is somehow an expensive operation while bool() can short-circuit, but none of the Python builtin datastructures work that way (len() gets the length from the ob_size attribute, no traversal is needed). Moreover, with small lists this wouldn't be significant, and the consistency in the following case is arguably more important:
if len(a) == 0: pass
elif len(a) == 1: pass
elif len(a) == 2: pass
else: pass
Another example is that assert len(errors) == 0 is arguably more intuitive than assert not errors.
IMHO this test should not be on by default.
@PCManticore why was this closed?
@acannon828 #1473 was merged. Although it does not provide an actual suggestion per se, this clears the ambiguity that led to this issue in the first place.
By the way, none of collections.abc classes states __bool__ method. In other words, how can I be sure that I can use bool(seq) if I know that it's a collections.abc.Collection? Moreso, some libraries declire that it's forbidden to check bool(collection) for their classes even they follow and "implement" this interface.
I think we should take PEP literally here. It says "don't use if len(seq) (relying on the "truthiness" of integers), it doesn't say "don't use len(seq) == n)".
@timokau I'm not sure I understand your statement. Regarding the use of len, PEP 8 comes down to this, verbatim:
- 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):
The statement "don't use len(seq)" (as a condition value) seems to have come from PyLint rather than PEP. The real confusion comes when the lint len-as-condition is triggered even when we do not assume the truthiness of anything but the output of the comparison operator: len(seq) == 0 or len(seq) > 0 would just raise "don't use len(seq) as condition value" all the same.
Yes that is exactly my point. I think there should be no warning when explicitly comparing the length with something.
Ah, I see your point now. I agree that triggering the lint with the condition len(seq) but _not_ with len(seq) == 0 would be less surprising. On the other hand, one might still argue that by writing len(seq) == 0, we're not relying on the "truthiness" of the sequence, as recommended by these guidelines.
It might be worth filing about the behaviour of this lint in a separate issue, since this one was initially focused on the lint's message, which has since then been improved with #1473.
Most helpful comment
This was apparently derived from PEP8, but note that PEP8 also says "a foolish consistency is the hobgoblin of small minds". It goes too far to claim that using
len(..) == 0as a condition is incorrect. There is a theoretical gain in efficiency, whenlen()is somehow an expensive operation whilebool()can short-circuit, but none of the Python builtin datastructures work that way (len()gets the length from theob_sizeattribute, no traversal is needed). Moreover, with small lists this wouldn't be significant, and the consistency in the following case is arguably more important:Another example is that
assert len(errors) == 0is arguably more intuitive thanassert not errors.IMHO this test should not be on by default.