14

what is the best way to turn a list into bool value? I am looking for something like:

return eval_bool(my_list)

I have a custom container in which I implement the __nonzero__ method which is supposed to work like this:

if self.my_list:
    return True
return False

But is it pythonic enough? :) Anyway, I am curious how Python interprets the value of the list in the if statement because this code works differently:

return my_list == True

J.

4 Answers 4

28

Just use:

bool(my_list)

Which evaluates it as Python "truthiness" and returns a real Boolean.

Sign up to request clarification or add additional context in comments.

4 Comments

While bool can be used, it's more Pythonic to just call if my_list: and let Python determine whether my_list should evaluate to True or False.
@SimeonVisser: Why is if my_list: return True\nreturn False more pythonic than return bool(my_list)?
It's just not common to write if bool(my_list): when you can also write if my_list:. In most cases, you only need to check whether the list is empty or not, you don't really need a boolean value. Python can see that you're evaluating an if statement and it calls bool() itself. If you really then a boolean value (for example, as output) then bool(my_list) is fine of course.
@SimeonVisser the goal here is not to have conditional logic at all, but to return a boolean.
5

99.9% of the time, performance doesn't matter, so just use bool(my_list) as Keith suggests.

In the cases where performance does matter though, the nature of bool means it's actually quite slow, at least on the CPython reference interpreter. It has to go through generalized function call paths, to generalized constructor paths, to generalized argument parsing for 0-1 arguments (and in all but the most recent versions of Python, checking for keyword arguments), all to eventually just increment as reference count on a singleton and return it.

You can see how much this costs with ipython microbenchmarks (on my Windows x64 3.6.3 build):

In [1]: %%timeit -r5 l = []
   ...: bool(l)
   ...:
118 ns ± 0.808 ns per loop (mean ± std. dev. of 5 runs, 10000000 loops each)
In [11]: %%timeit -r5 l = [1]
    ...: bool(l)
    ...:
117 ns ± 0.306 ns per loop (mean ± std. dev. of 5 runs, 10000000 loops each)

It may not be obvious, but even on my relatively weak laptop, 117-118 nanoseconds just to determine truthiness is a bit much. Luckily, there are a couple other options. One is to abuse syntax to go through a dedicated path for truthiness evaluation (from here on out, I'll just test the empty list, the timings are basically identical either way):

In [3]: %%timeit -r5 l = []
   ...: not not l
   ...:
25 ns ± 0.289 ns per loop (mean ± std. dev. of 5 runs, 10000000 loops each)

That's a vast improvement; it takes roughly one fifth the time. On Python 3, using True if l else False also works with equal speed, but it's much slower than not not on Python 2, where True and False aren't protected literals, just built-in names that must be loaded dynamically each time.

Still, it's not perfect; sometimes you need a callable, e.g. to convert a lot of values to bool via a callback function (e.g. with map). Luckily, the operator module has you covered with operator.truth; while it's still a callable with all the overhead that entails, it's not a constructor, it takes exactly one argument (not 0-1), and it doesn't allow keyword arguments, all of which cost a surprising amount on the CPython reference interpreter. So when you can't use implicit truthiness testing or syntax based conversion with not not, and you still need the speed, operator.truth has you covered:

In [4]: from operator import truth

In [5]: %%timeit -r5 l = []
   ...: truth(l)
   ...:
52.1 ns ± 1.1 ns per loop (mean ± std. dev. of 5 runs, 10000000 loops each)

Twice as long as not not, but if you're using it with built-ins that call it repeatedly (like map) being able to push all the work to the C layer, avoiding byte code execution entirely, can still make it a win, and it's still well under half as costly as bool() itself.

Reiterating my earlier point though: 99.9% of the time, performance doesn't matter, so just use bool(my_list) as Keith suggests. I only mention this because I once had a scenario where that boolean conversion really was the hottest point in my code (verified through profiling), and using implicit truthiness testing (not even converting, just returning the list with the caller doing if myfunc():) shaved 30% off the runtime, and returning not not of the list still got nearly a 20% savings.

Comments

1

If len(my_list) == 0 it is returned as false, otherwise it is true. It is completely pythonic to write:

return len(my_list)

which although it is returned as an integer, evaluates as true for non zero lengths, and false otherwise.

2 Comments

That will return the integer value, however, and we want a boolean.
it works but it violates pep 8: 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)
1

You can use ternary "if" operator. Google says it supported since 2.5

foo = True if your_list else False

1 Comment

Note: In Python 2, at least for the CPython reference interpreter, this is surprisingly slow, because both True and False are global built-ins that must be loaded from the built-in namespace (which involves a pair of dictionary lookups, one for globals, then a second in builtins when they're not found), not literal constants. In Python 3, they are literal constants, which only require a cheap LOAD_CONST instruction to load (which boils down to a single C level array lookup), so this is one of the two fastest ways to convert to a bool (the other being not not your_list).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.