11

I am making an AJAX call and passing variable pub in it which could be 1 or 0.

As a beginner I want to be double sure of the variable type that is coming in. I am aware I can easily convert to int() and the problem is actually not with AJAX result but it led to this question.

My code:

if pub == 1 or pub == '1':
    #execute funcA()

But the above is not so pythonic for me so I tried:

if pub in [1,'1']:
    #execute funcA()

Which of the above code is better in terms of:

  1. Performance(speed).
  2. Best practice.
  3. Memory usage.
Yax
  • 2,127
  • 5
  • 27
  • 53
  • 2
    As you are making a Ajax call so it will be serialized which means it will be always `'1'` – Tanveer Alam Jul 15 '15 at 05:40
  • 2
    Why have you tagged both 2.7 and 3.x? – thefourtheye Jul 15 '15 at 05:43
  • based on http://stackoverflow.com/questions/15112125/how-do-i-test-one-variable-against-multiple-values I would use pub in {1,1} or pub in (1,-1) –  Jul 15 '15 at 06:00
  • Might help http://stackoverflow.com/questions/30277347/if-else-statements-accepting-strings-in-both-capital-and-lower-case-letters-in-p/30277407#30277407 – Tanveer Alam Jul 15 '15 at 06:43

6 Answers6

17

Performance: in is better

timeit.timeit("pub='1'; pub == 1 or pub == '1'")
0.07568907737731934
timeit.timeit("pub='1'; pub in[1, '1']")
0.04272890090942383
timeit.timeit("pub=1; pub == 1 or pub == '1'")
0.07502007484436035
timeit.timeit("pub=1; pub in[1, '1']")
0.07035684585571289

#other options
timeit.timeit("pub='1'; pub in (1,'1')")
0.04643988609313965
timeit.timeit("pub='1'; pub in {1,'1'}")
0.17076611518859863
timeit.timeit("pub=1; pub in (1,'1')")
0.047419071197509766
timeit.timeit("pub=1; pub in {1,'1'}")
0.1770930290222168

So, {} > or > [] > () based on performance.

Practice: in is preferred as it is less to type. (), [], {} equally good based on practice

Memory:

sys.getsizeof([1,"1"])
88
sys.getsizeof("1",1)
38

#other options
sys.getsizeof(("1",1))
72
sys.getsizeof({"1",1})
232

So, {} > [] > () > or based on memory

Although not asked,, good to know:

Functionality: Value equality and not reference equality

in is just sequential checking equality ==. So similar. in uses == and not is. What I mean to say is this:

>>> a = [1,2,3]
>>> b = [1,a]
>>> b
[1, [1, 2, 3]]
>>> 1 in b
True
>>> a in b
True
>>> [1,2,3] in b
True

So it is implemented not like this:

>>> for i in b:
...     print [1,2,3] is i
... 
False
False

is will return True if two variables point to the same object, == if the objects referred to by the variables are equal. in uses ==

sinhayash
  • 2,693
  • 4
  • 19
  • 51
  • 2
    *"**`in` uses `==`**"* - only if `is` doesn't match anything. Also note that your `timeit` includes the cost of creating the object (e.g. set literal), which isn't necessarily representative. – jonrsharpe Jul 15 '15 at 06:51
8

This code is better

if pub in [1,'1']:
    #execute funcA()

because it's slightly faster but mainly because it is not redundant. The variable pub appears only once there.

dlask
  • 8,776
  • 1
  • 26
  • 30
  • This is also nice because it allows you to easily add more values in the future, while keeping it readable. `if pub in [1, '1', 'one', 'uno']:` – dmertl Jul 18 '17 at 20:44
3

So performance wise in is better :

timeit.timeit("pub='1'; pub == 1 or pub == '1'")
0.16224503758795805
timeit.timeit("pub='1'; pub in[1, '1']")
0.13723585976354258
timeit.timeit("pub=1; pub == 1 or pub == '1'")
0.07986264585216674
timeit.timeit("pub=1; pub in[1, '1']")
0.07246544186018866

And as per memory space the if is better since list uses slightly more memory

sys.getsizeof([1,"1"])
44
sys.getsizeof(1)
12
sys.getsizeof("1")
22 
sys.getsizeof("1",1)
22

This is due to the fact that when even empty list is created it takes memory space

sys.getsizeof([])
36

I don't know about the best practice aspect

For me the most pythonic way would be is to use in since it reduces the typing

The6thSense
  • 8,103
  • 8
  • 31
  • 65
1

1. Performance:

>>> timeit.timeit("pub=1; pub == 1 or pub == '1'", number=10000)
0.0017161369323730469
>>> timeit.timeit("pub=1; pub in[1, '1']", number=10000)
0.0013611316680908203

2. Best Practice: It's good to write programme in a pythonic way I prefer (pub in [1, '1'])

3. Memory Usage: number 1 and string '1' is always cached in python, you can verify the refcount for these objects. So ideally it won't take any extra memory.

>>> sys.getrefcount(1)
833
>>> sys.getrefcount('1')
16

If you use list that needs more memory needs to be allocated to refer these cached objects. (below is in 64 bit type)

>>> sys.getsizeof([1, '1'])
88

These 88 bytes of memory you are gonna allocate extra than the other way of doing.

I would suggest to go with :

if pub in [1,'1']:
    #execute funcA()
gsb-eng
  • 1,211
  • 1
  • 9
  • 16
0

In speed:
in is faster and by a lot.
To prove it, here is the code.

from datetime import datetime

start0 = datetime.now()
pub = 1
if pub == 1 or pub == '1':
    # execute funcA()
    pass
end0 = datetime.now() - start0
print end0
start1 = datetime.now()

if pub in [1, '1']:
    # execute funcA()
    pass
end1 = datetime.now() - start1
print end1
print end0 - end1

Output:

0:00:00.000045
0:00:00.000007
0:00:00.000038

In space: == is a whole lot better.
in takes O(2) space while == takes O(1) space

According to me, the best practice is using in since it is a lot faster and saves a lot of typing

rrao
  • 297
  • 4
  • 11
0

Not really true. If you switch the order you would see different result, just put in order below:

pub = 1
if pub in [1, '1']:
    # execute funcA()
    pass
end1 = datetime.now() - start1
print end1
print end0 - end1

start0 = datetime.now()
if pub == 1 or pub == '1':
    # execute funcA()
    pass
end0 = datetime.now() - start0
print end0
start1 = datetime.now()
Alex
  • 11
  • 1