Reputation: 28888
I was reading some code and I noticed that this code has many of these lines:
try:
rv = somefunction()
except SomeException, e:
rv = 0
if rv == 0:
doSomething() ...
It seemed to me that using this style of comparison operations is bound to be slower than:
try:
rv = somefunction()
except SomeException, e:
rv = None
if is not None:
doSomething()
...
Upvotes: 1
Views: 135
Reputation: 12401
Maybe it depends on whether you are in python 2 or python 3. In python 2, the only 'slow' operation is `== None'. I thought it was because integers in low ranges were precreated objects, but in actuality that didn't matter.
In [53]: x = 0
In [54]: %timeit x is 0
10000000 loops, best of 3: 38 ns per loop
In [55]: %timeit x == 0
10000000 loops, best of 3: 36.5 ns per loop
In [56]: x = 1
In [57]: %timeit x is 0
10000000 loops, best of 3: 37.3 ns per loop
In [58]: %timeit x == 0
10000000 loops, best of 3: 36.5 ns per loop
In [59]: %timeit x is None
10000000 loops, best of 3: 38.1 ns per loop
In [60]: %timeit x == None
10000000 loops, best of 3: 82.9 ns per loop
Now, in the first 3 cases, x is an int, which is the same type in the first 3 cases, and not in the last. So tried one additional thing, making x a string, so it would not match type with 0:
In [62]: x = 'x'
In [63]: %timeit x is 0
10000000 loops, best of 3: 38.7 ns per loop
In [64]: %timeit x == 0
10000000 loops, best of 3: 92.5 ns per loop
In [65]: %timeit x is None
10000000 loops, best of 3: 39.1 ns per loop
In [66]: %timeit x == None
10000000 loops, best of 3: 77.1 ns per loop
In this case, the 'is' is still pretty fast, no matter what the types, while mixed type equality checking is slower. This makes sense, as 'is' is just an equality check on the id, while equals can be arbitrarily slow.
Meaning that if you really concerned about this (which you probably don't need to be as mentioned, unless this is in an inner loop), you should create a sentinel object (of any time), and then use the is
operator to check against it directly. None
is a convenient one as long as it's not a valid value; 0
or -1
can fulfill the same role. But it doesn't have to be those.
Upvotes: 1
Reputation: 122161
Would it be more efficient to just do:
try:
rv = somefunction()
except SomeException, e:
doSomething() ...
You may still need to set rv = 0
if an integer value is needed elsewhere, which is a limiting factor on your examples above.
Upvotes: 2
Reputation: 28888
To show my mate this is possibly true, I did some benchmarking with None, 0
and False
:
I have read before this question, When is the `==` operator not equivalent to the `is` operator? (Python). And I even added some benchmarking to try and convince my mates that this could be optimized:
In [92]: def TestInt():
....: i = 0
....: if i:
....: pass
....:
In [93]: def TestBool():
....: i = False
....: if i:
....: pass
....:
In [95]: def TestNone():
....: i = None
....: if i:
....: pass
....:
In [97]: timeit.timeit(TestInt, number=10**5)
Out[97]: 0.01352691650390625
In [98]: timeit.timeit(TestBool, number=10**5)
Out[98]: 0.014671087265014648
In [99]: timeit.timeit(TestNone, number=10**5)
Out[99]: 0.009851932525634766
Obviously comparing if an object is not None
is always a little bit faster!
Upvotes: 0