Charlie Clark
Charlie Clark

Reputation: 19507

What's the best way of distinguishing bools from numbers in Python?

I have an application where I need to be able to distinguish between numbers and bools as quickly as possible. What are the alternatives apart from running isinstance(value, bool) first?

Edit: Thanks for the suggestions. Actually, what I want to be able to do have a check for numbers that leaves out bools so that I can reorder my checks (numbers are far more prevalent) and improve my negacalls. isinstance() itself is fast enough. The x is True or x is False is intriguing.

Upvotes: 5

Views: 144

Answers (2)

Boldewyn
Boldewyn

Reputation: 82734

So, Padraic Cunningham suggests, that the following might be a bit faster. My own quick experiments with cProfile-ing it haven't shown any difference:

isbool = value is True or value is False

I assume that's as fast as you can get: Two non-type-coercing comparisons.

Edit: I replayed the timing tests from @user 5061 and added my statement. This is my result:

>>> import timeit
>>> stmt1 = "isinstance(123, bool)"
>>> stmt2 = "123 is True or 123 is False"
>>> t1 = timeit.timeit(stmt1)
>>> t2 = timeit.timeit(stmt2)
>>> print t1
0.172112941742
>>> print t2
0.0690350532532

Edit 2: Note, that I'm using Python 2.7 here. @user 5061 might use Python 3 (telling from the print() function), so any solution provided here should be tested by OP before putting in production, for YMMV.

Upvotes: 5

user
user

Reputation: 5696

Testing done using Python 3.4.

stmt5 was suggested by grc. stmt3 was suggested by boldewyn and seems to be the fastest option in most cases (unless data consists mostly of ints):

import timeit

setup = "a = 123; b = True"

stmt1 = "isinstance(a, bool) ; isinstance(b, bool)"
stmt2 = "isinstance(a, int) ; isinstance(b, int)"

stmt3 = "a is True or a is False; b is True or b is False"

stmt4 = "type(a) is bool; type(b) is bool"  
stmt5 = "a.__class__ is bool ; b.__class__ is bool"


repetitions = 10**6
t1 = timeit.timeit(stmt1, setup=setup, number=repetitions)
t2 = timeit.timeit(stmt2, setup=setup, number=repetitions)
t3 = timeit.timeit(stmt3, setup=setup, number=repetitions)
t4 = timeit.timeit(stmt4, setup=setup, number=repetitions)
t5 = timeit.timeit(stmt5, setup=setup, number=repetitions)


print(t1)
print(t2)
print(t3)
print(t4)
print(t5)

Results:

0.251072
0.190989
0.037483
0.140759
0.08480

Note that isinstance(123, bool) is slower than isinstance(123, int). Therefore i had to use both a and b. This is of course assuming that you have an equal amount of ints and bools.

Also, as grc suggested in the comments "True is faster because it short-circuits after the first comparison", so if you use b = False you ll get a slightly slower time for stmt3.


Only usable if the data does not contain 0, 0.0, 1, 1.0:

setup = "a = 123; b = True; s = {True, False}"

stmt3 = "a is True or a is False; b is True or b is False"
stmt6 = "a in s ; b in s"

Result:

0.037680588
0.03936778

If your data consists mostly of integers, this becomes the fastest option (0.045375 vs 0.0390963).

Upvotes: 3

Related Questions