1

So if I wish to compare numbers in Python, say, to check if the number falls in the inclusive range of 2 to 100.
Which of the following method is most preferable and why?

Using comparitive operators?

if(n>=2 and n<=100):
    print("Okay")

or using range() function?

if(n in range(2,101)):
    print("Okay")

Also would your answer change if the comparison if for very large numbers?

dawg
  • 80,841
  • 17
  • 117
  • 187
Sumaiya A
  • 118
  • 10
  • 2
    First is better, second is slower (even more for large numbers) and doesn't work for floats. – Michael Butscher Oct 29 '19 at 04:04
  • 3
    @MichaelButscher the speed difference should be relatively small no matter how large the numbers are. Python has to allocate the `range` object is all. I'm sure its `__contains__` method is basically just this same double inequality. – Him Oct 29 '19 at 04:13
  • 3
    @MichaelButscher A `range` object is not a list. It doesn't matter how many elements it has. See https://stackoverflow.com/questions/30081275/why-is-1000000000000000-in-range1000000000000001-so-fast-in-python-3?rq=1 – Selcuk Oct 29 '19 at 04:16
  • 1
    Scott, Selcuk, Right, I really forgot that it doesn't have to process the iterator until the number is/isn't found. – Michael Butscher Oct 29 '19 at 04:20
  • `if(2 <= n <= 100):` is usually a better way to write your first condition, and is equivalent to `if(2 <= n and n <= 100):` In addition, just two conditions need to be checked, whereas `if(n in range(2, 101)):` requires testing `n` against each value. – Alexander Oct 29 '19 at 04:20
  • 2
    @Alexander Actually the `and` variant is slightly more performant: https://stackoverflow.com/questions/48375753/why-are-chained-operator-expressions-slower-than-their-expanded-equivalent . I agree with the readability though. – Selcuk Oct 29 '19 at 04:22
  • Further reference to this answer by Martijn Pieters shows that inclusion in a range is calculated rather than each value tested individually. It is still slower, however, compared to the first condition. https://stackoverflow.com/questions/30081275/why-is-1000000000000000-in-range1000000000000001-so-fast-in-python-3/30081318#30081318 – Alexander Oct 29 '19 at 04:34
  • 1
    Is this Python 3 or Python 2? If it is Python **2** then don't use the `range` method since the entire list will be produced. – dawg Oct 29 '19 at 04:46
  • 1
    @dawg `print()` suggests that it's Python 3.x. Can't be certain though. – Selcuk Oct 29 '19 at 05:01

2 Answers2

6

In this case the pythonic way would be to use comparison chaining:

if 2 <= n <= 100:
    print("Okay")
juanpa.arrivillaga
  • 65,257
  • 7
  • 88
  • 122
  • My question isn't about readability or ways to write comparitive operators. I am more interested to know the performance wise impact of comparison operator v/s range function – Sumaiya A Oct 29 '19 at 05:10
  • @SumaiyaA the performance impacts will be practically negligible, and what is preventing you from timing it yourself? However, one big difference is that `range` does not support efficient containment checks for non-`int` objects, so say, a `float` will be much slower, algorithmically. – juanpa.arrivillaga Oct 30 '19 at 22:33
3

The difference is tiny, but here are some comparisons (I would put this in a comment, but it is too verbose):

n = 999_999_999

%%timeit -n 100000
if 2 <= n <= 1_000_000_000:
    pass
# 85.8 ns ± 13.9 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%%timeit -n 100000
if 2 <= n and n <= 1_000_000_000:
    pass
# 81.3 ns ± 15.6 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)

%%timeit -n 100000
if n in range(1_000_000_000):
    pass
# 360 ns ± 29.4 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)
Alexander
  • 87,529
  • 23
  • 162
  • 169
  • Note, try using `n = 999999999.0` – juanpa.arrivillaga Oct 30 '19 at 22:34
  • It will obviously slow the comparisons if `n` is a float, but doesn't make sense within the context of the question, i.e. `if(n in range(2,101))`. – Alexander Oct 30 '19 at 22:53
  • No, using an object that isn't an `int` will by-pass the quick membership test and simply iterate over the `range` object. IOW, membership testing with `int` objects for `range` objects is constant time, but linear time for any other type of object – juanpa.arrivillaga Oct 30 '19 at 22:55
  • Understood, and a good point to raise, but IMO outside the scope of the question where `n` is inferred to be an integer (because it is being tested against a range of integers). – Alexander Oct 30 '19 at 23:08