Python try/except Can Be a Performant Way to Check for Type
Say, you want to do some math with a variable. Math implies that the variable in the operation is a numerical value (we’ll say in the typical case… don’t mean tweet me…). Before doing math operations, you might want to sanity check the variable so that your code will not blow up if the input is not numerical.
isinstance is a go-to for asking this generally. You just use it like
isinstance(some_variable, Type_Or_Class) or to check a variable against multiple instance types you would just change the second argument to a tuple like
isinstance(some_variable, (Type_Or_Class1, Type_Or_Class2)).
So, the usage would be as a pre-check to validation:
def validate(foobar): if not isinstance(foobar, (int, float)): raise ValueError("This input must be a number!") return foobar + 10
As a fun-fact:
int works here since it’s in the method resolution order (mro) for the value.
type(123).__mro__ > (<class 'int'>, <class 'object'>)
An opposite way to look at this is to ask for forgiveness rather than permission.
def validate(foobar): try: return foobar + 10 except: raise ValueError("This input must be a number!")
Whenever I stumble upon something like this, I like to break out
timeit to compare.
import timeit N_ITERATIONS = 10000000 setup = """ # code that sets stuff up, that won't be included in profiling from datetime import datetime unix_epoch = datetime.now().timestamp() """ # good 'ol isinstance test = """ isinstance(unix_epoch, (int, float)) """ print(timeit.timeit(setup=setup, stmt=test, number=N_ITERATIONS)) # try to add to a number test = """ try: unix_epoch += 1 except TypeError: raise ValueError("This input must be a number!") """ print(timeit.timeit(setup=setup, stmt=test, number=N_ITERATIONS)) # just to be silly, also use divide test = """ try: unix_epoch / 2 except TypeError: raise ValueError("This input must be a number!") """ print(timeit.timeit(setup=setup, stmt=test, number=N_ITERATIONS))
On a random EC2 instance I SSH’ed into:
1.5472514729946852 0.43879494071006775 0.43832130171358585
My 2.7 GHz Quad-Core Intel Core i7 MacBook Pro:
1.748314122 0.5496298039999998 0.5205081649999999
Funny enough, the silly thing i tried was actually the fastest. Since I was using this code in a REST API serializer that gets millions of hits a day, I went with faster.