Reputation: 27073
The Zen of Python says "Explicit is better than implicit". Yet the "pythonic" way to check for emptiness is using implicit booleaness:
if not some_sequence:
some_sequence.fill_sequence()
This will be true if some_sequence
is an empty sequence, but also if it is None
or 0
.
Compare with a theoretical explicit emptiness check:
if some_sequence is Empty:
some_sequence.fill_sequence()
With some unfavorably chosen variable name the implicit booleaness to check for emptiness gets even more confusing:
if saved:
mess_up()
Compare with:
if saved is not Empty:
mess_up()
See also: "Python: What is the best way to check if a list is empty?". I find it ironic that the most voted answer claims that implicit is pythonic.
So is there a higher reason why there is no explicit emptiness check, like for example is Empty
in Python?
Upvotes: 23
Views: 3025
Reputation: 2755
There is an explicit emptyness check for iterables in Python. It is spelled not
. What's implicit there? not
gives True when iterable is empty, and gives False when it is nonempty.
What exactly do you object to? A name? As others have told you, it's certainly better than is Empty
. And it's not so ungrammatical: considering how things are usually named in Python, we might imagine a sequence called widgets
, containing, surprisingly, some widgets. Then,
if not widgets:
can be read as "if there are no widgets...".
Or do you object the length? Explicit doesn't mean verbose, those are two different concepts. Python does not have addition
method, it has +
operator, that is completely explicit if you know the type you're applying it to. The same thing with not
.
Upvotes: 0
Reputation: 27073
The reason why there is no is Empty
is astoundingly simple once you understand what the is
operator does.
From the python manual:
The operators
is
andis not
test for object identity:x is y
is true if and only ifx
andy
are the same object.x is not y
yields the inverse truth value.
That means some_sequence is Empty
checks whether some_sequence
is the same object as Empty
. That cannot work the way you suggested.
Consider the following example:
>>> a = []
>>> b = {}
Now let's pretend there is this is Empty
construct in python:
>>> a is Empty
True
>>> b is Empty
True
But since the is
operator does identity check that means that a
and b
are identical to Empty
. That in turn must mean that a
and b
are identical, but they are not:
>>> a is b
False
So to answer your question "why is there no is Empty
in python?": because is
does identity check.
In order to have the is Empty
construct you must either hack the is
operator to mean something else or create some magical Empty
object which somehow detects empty collections and then be identical to them.
Rather than asking why there is no is Empty
you should ask why there is no builtin function isempty()
which calls the special method __isempty__()
.
So instead of using implicit booleaness:
if saved:
mess_up()
we have explicit empty check:
if not isempty(saved):
mess_up()
where the class of saved
has an __isempty__()
method implemented to some sane logic.
I find that far better than using implicit booleaness for emptyness check.
Of course you can easily define your own isempty()
function:
def isempty(collection):
try:
return collection.__isempty__()
except AttributeError:
# fall back to implicit booleaness but check for common pitfalls
if collection is None:
raise TypeError('None cannot be empty')
if collection is False:
raise TypeError('False cannot be empty')
if collection == 0:
raise TypeError('0 cannot be empty')
return bool(collection)
and then define an __isempty__()
method which returns a boolean for all your collection classes.
Upvotes: 15
Reputation: 5555
Consider that Lisp has been using () empty list or its symbol NIL quite some years as False and T or anything not NIL as True, but generally computation of Truth already produced some useful result that need not be reproduce if needed. Look also partition method of strings, where middle result works very nicely as while control with the non-empty is True convention.
I try generally avoid using of len as it is most times very expensive in tight loops. It is often worth while to update length value of result in program logic instead of recalculating length.
For me I would prefer Python to have False as () or [] instead of 0, but that is how it is. Then it would be more natural to use not [] as not empty. But now () is not [] is True so you could use:
emptyset = set([])
if myset == emptyset:
If you want to be explicit of the empty set case (not myset is set([]))
I myself quite like the if not myset as my commenter.
Now came to my mind that maybe this is closest to explicit not_empty:
if any(x in myset for x in myset): print "set is not empty"
and so is empty would be:
if not any(x in myset for x in myset): print "set is empty"
Upvotes: 0
Reputation: 2654
I agree that sometimes if foo:
isn't explicit for me when I really want to tell the reader of the code that it's emptiness I'm testing. In those cases, I use if len(foo):
. Explicit enough.
I 100% agree with Alex w.r.t is Empty
being unpythonic.
Upvotes: 6
Reputation: 882421
Polymorphism in if foo:
and if not foo:
isn't a violation of "implicit vs explicit": it explicitly delegates to the object being checked the task of knowing whether it's true or false. What that means (and how best to check it) obviously does and must depend on the object's type, so the style guide mandates the delegation -- having application-level code arrogantly asserts it knows better than the object would be the height of folly.
Moreover, X is Whatever
always, invariably means that X is exactly the same object as Whatever. Making a totally unique exception for Empty
or any other specific value of Whatever
would be absurd -- hard to imagine a more unPythonic approach. And "being exactly the same object" is obviously transitive -- so you could never any more have distinct empty lists, empty sets, empty dicts... congratulations, you've just designed a completely unusable and useless language, where every empty container crazily "collapses" to a single empty container object (just imagine the fun when somebody tries to mutate an empty container...?!).
Upvotes: 21