oz123
oz123

Reputation: 28888

Python comparison operation, if and None

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

Answers (3)

Corley Brigman
Corley Brigman

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

jonrsharpe
jonrsharpe

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

oz123
oz123

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

Related Questions