开发者

Why implicitly check for emptiness in Python? [closed]

As it currently stands, this question is not a good fit for our Q&A format. We expect answers to be supported by facts, references, or expertise, but this question will likely solicit debate, arguments, polling, or extended discussion. If you feel that this question can be improved and possibly reopened, visit the help center for guidance. Closed 11 years ago.

The Zen of Python says that explicit is better than implicit.

Yet the Pythonic way of checking a collection c for emptiness is:

if not c:
    # ...

and checking if a collection is not empty is done like:

if c:
    # ...

ditto for anything that can have "zeroness" or "emptiness" (tuples, integers, strings, None, etc)

What is the purpose of this? Will my code be buggier if I don't do this? Or does it enable more use开发者_运维问答 cases (i.e: some kind of polymorphism) since people can override these boolean coercions?


This best practice is not without reason.

When testing if object: you are basically calling the objects __bool__ method, which can be overridden and implemented according to object behavior.

For example, the __bool__ method on collections (__nonzero__ in Python 2) will return a boolean value based on whether the collection is empty or not.

(Reference: http://docs.python.org/reference/datamodel.html)


Possibly trumped by the first and third items:

  • Beautiful is better than ugly.
  • Simple is better than complex.


"Simple is better than complex."

"Readability counts."

Take for example if users -- it is more readable that if len(users) == 0


if c:
    # ...

is explicit. The "if" explicitly states that the expression following will be evaluated in boolean context.

It is fair to argue that

if c == 0:
    # ...

is clearer, and a programming novice might agree.

But to an experienced programmer (this one at least) the latter is not clearer, it is redundant. I already know c will be compared with 0 because of the "if"; I don't need to be told twice.


Implicit boolean polymorphism is a part of many languages. In fact, the idiom

if msg:
    print str(len(msg)) + ' char message: ' + msg

arguably comes from c!

void print_msg(char * msg) {
    if (msg) {
        printf("%d char message: %s", (int) strlen(msg), msg);
    }
}

An unallocated pointer should contain NULL, which conveniently evaluates to false, allowing us to avoid a segmentation fault.

This is such a fundamental concept that it would hamper python to reject it. In fact, given the fairly clumsy version of boolean polymorphism available in c, it's immediately clear (to me at least) that python has made this behavior much more explicit by allowing any type to have a customizable, well-defined boolean conversion via __nonzero__.


If you prefer you can type if len(lst) > 0, but what would be the point? Python does use some conventions, one of which is that empty containers are considered falseish.

You can customize this with object.__nonzero__(self):

Called to implement truth value testing and the built-in operation bool(); should return False or True, or their integer equivalents 0 or 1. When this method is not defined, __len__() is called, if it is defined, and the object is considered true if its result is nonzero. If a class defines neither __len__() nor __nonzero__(), all its instances are considered true.


Others have already noted that this is a logical extension of the tradition (at least as early as C, perhaps earlier) that zero is false in a Boolean context, and nonzero is true. Others have also already noted that in Python you can achieve some special effects with customized magic methods and such. (And this does directly answer your question "does it enable more use cases?") Others have already noted that experienced Python programmers will have learned this convention and be used to the convention, so it is perfectly obvious and explicit to them.

But honestly, if you don't like that convention, and you are just programming for your own enjoyment and benefit, simply don't follow it. It is much, much better to be explicit, clear, and redundant than it is to be obfuscated, and it's virtually always better to err on the side of redundancy than obfuscation.

That said, when it comes down to it, it's not a difficult convention to learn, and if you are coding as part of a group project, it is best to stick with the project's conventions, even if you disagree with them.


Empty lists evaluating to False and non-empty lists evaluating to True is such a central Python convention that it is explicit enough. If the context of the if-statement even communicates the fact that c is a list, len(c) == 0 wouldn't be much more explicit.

I think len(c) == 0 only is more explicit if you really want to check the length and not for magic zeroness or emptiness because their evaluation may differ from the length check.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜