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.
Just use:
bool(my_list)
Which evaluates it as Python "truthiness" and returns a real Boolean.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With