question about True values

Carl Banks pavlovevidence at gmail.com
Sun Oct 29 02:31:23 EST 2006


Steven D'Aprano wrote:
> Carl Banks:
> > Overall, your objections don't really apply, since you're arguing what
> > ought to be whereas my argument is pragmatic.  Practically speaking, in
> > realistic situations, "if len(a)>0" will work for a wider range of types
> > than "if a:".
>
> Well, that's a quantitative claim you're making there. Have you
> actually gone through, say, the built in types and checked how many
> have a length versus how many work in a truth-context?

No, and it's irrelevant to my argument.

For some reason, people seem to think it's absolutely wonderful that
you can write "if X:" somewhere, and that this "works" whether X is a
list or an int or any other object, as if "working" for both ints and
lists was actually useful.

Well, it's not.

You see, presumably you have to do something with X.  And in realistic
code, there's not a lot of stuff you can do with that works for both
container types like lists and dict, and atomic types like ints and
floats.  All you could do is call generic object protocol stuff like
id() or str().  There's some odd operations that can work for both a
container and an atomic (addition); even so, it's rare that a given
piece of code would actually be useful for both containers and atomics.
 (I mean, you could pass lists into a function such as the following,
but would it be useful?)

def binomial3(a,b,c,d):
    return a + 3*b + 3*c + d

What I'm saying is, the fact that "if X:" "works" for almost any type
is big ol' red herring.  The only thing that really matters is if it
works for types that _actually have some realistic overlapping uses_.

So let's do your little exercise keeping that in mind.  Let's look at
realistic uses of containers.  Suppose we have a function such as this:

def f(X):
    if not X:
        return
    do_some_indexing(X[2],X[4])

We see that we subscript X.  Now, you can't subscript an int, so if
we're going to count number of types that support "if a:" versus the
number that support "if len(a)>0", we're not going to consider ints.
When deciding whether we should go with "if a:" or "if len(a)>0", we
should only count types that support indexing.

Objects that support indexing and work with "if a:":
lists,tuples,dicts,strings,xrange,collections.deque,array.array

Objects that support indexing and work with "if len(a)>0":
lists,tuples,dicts,strings,xrange,collections.deque,array.array ...
numpy arrays

Another thing containers do a lot is iteration.

Objects that support iteration and work with "if a:"
lists,tuples,dicts,sets,strings,xrange,collections.deque,array.array

Objects that support iteration and work with "if len(a)>0:"
lists,tuples,dicts,sets,strings,xrange,collections.deque,array.array
... numpy arrays

What can we conclude?  If you're indexing or iterating, "if a:" and "if
len(a)>0:" are equally successful for built-in types, but "if
len(a)>0:" also works for numpy arrays.  If your only measure of
success is how many classes the emptiness tests works for, then "if
len(a)>0:" wins.  This is just an example; we haven't looked at all
possible uses of containers.  There will be a few cases where "if a:"
works but "if len(a)>0:" doesn't.  But it should be pretty clear where
this is headed.

So the question is:  Do you want use "if len(a)>0:", so that in a lot
of cases your code can also work if someone wants to use a popular
third party package?  Or do you want to use "if a:", so that in rare
cases your code could also work with some builtin atomic types?


Carl Banks




More information about the Python-list mailing list