I made an interesting observation the other day. I was experimenting with various ways to get the "truthiness" of an object and the speed of each, and I noticed that not
is much faster than bool
.
>>> bool([5, 6, 7])
True
>>> bool([])
False
>>> not not [5, 6, 7]
True
>>> not not []
False
>>> import timeit
>>> from numpy import mean
>>> mean(timeit.repeat('bool(a)', 'a = [5, 6, 7]', repeat=10))
0.19072036743164061
>>> mean(timeit.repeat('bool(a)', 'a = []', repeat=10))
0.18562331199645996
>>> mean(timeit.repeat('not not a', 'a = [5, 6, 7]', repeat=10))
0.072056698799133304
>>> mean(timeit.repeat('not not a', 'a = []', repeat=10))
0.073475956916809082
>>> mean(timeit.repeat('not a', 'a = [5, 6, 7]', repeat=10))
0.043941426277160647
>>> mean(timeit.repeat('not a', 'a = []', repeat=10))
0.044287109375000001
We can see that using the bool
function is significantly slower than using the not
statement, even though ultimately they do the same thing (return the boolean state of the object). Now, we have all been told that in Python the function overhead is large, but I was not expecting this type of discrepancy in this case for the following reasons:
bool()
is a builtin function, meaning that it is written in C, and I would have expected this to have a rather low overheadnot
has to return the logical opposite of the object's "truthiness", so in theory it is doing a bit more work (but perhaps there is an implementation detail that gets around this)In my mind, because both functions are doing essentially the same thing all the extra time must be coming from the function overhead. If that is the case, why is it that a statement is able to avoid so much overhead compared to a function? If it is not the overhead, why is bool()
so much slower than not
?
UPDATE: Here are also the min times in addition to the mean.
>>> min(timeit.repeat('bool(a)', 'a = [5, 6, 7]', repeat=10))
0.18180489540100098
>>> min(timeit.repeat('bool(a)', 'a = []', repeat=10))
0.1821761131286621
>>> min(timeit.repeat('not not a', 'a = [5, 6, 7]', repeat=10))
0.0707249641418457
>>> min(timeit.repeat('not not a', 'a = []', repeat=10))
0.07100605964660645
>>> min(timeit.repeat('not a', 'a = [5, 6, 7]', repeat=10))
0.04264092445373535
>>> min(timeit.repeat('not a', 'a = []', repeat=10))
0.04357004165649414
Bool is smaller and hence can be faster if you are keeping large arrays of bools/ints, in terms of cache efficiency.
Booleans and integers are fasterIntegers and Booleans are generally much faster than strings. If your calculation produces a binary result (for example, yes/no, pass/fail, over/under), be sure to return a Boolean result rather than a string.
Python bool() Function The bool() function returns the boolean value of a specified object. The object will always return True, unless: The object is empty, like [], (), {} The object is False. The object is 0.
You can check if a value is either truthy or falsy with the built-in bool() function. According to the Python Documentation, this function: Returns a Boolean value, i.e. one of True or False .
(This is not supposed to be an answer, just documentation): These are the byte code sequences of the given expressions:
bool(a)
:
1 0 LOAD_NAME 0 (bool)
3 LOAD_NAME 1 (a)
6 CALL_FUNCTION 1 (1 positional, 0 keyword pair)
9 RETURN_VALUE
not a
:
1 0 LOAD_NAME 0 (a)
3 UNARY_NOT
4 RETURN_VALUE
not not a
:
1 0 LOAD_NAME 0 (a)
3 UNARY_NOT
4 UNARY_NOT
5 RETURN_VALUE
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