4

Often to save some time, I would like we to use n = len(s) in my local function. I am curious about which call is faster or they are the same?

while i < len(s):
  # do something

vs

while i < n:
  # do something

There should not be too much difference, but using len(s), we need to reach s first, then call s.length. This is O(1) + O(1). But using n, it is O(1). I assume so.

Pythoner
  • 5,265
  • 5
  • 33
  • 49
  • You could use the `dis` module and look at the byte code. You could also use `timeit` to benchmark it. I would be surprised if it made much difference. – John Coleman Nov 27 '18 at 21:10
  • 6
    `O(1) + O(1)` is still `O(1)`. You should profile your code to see if repeated calls to `len(s)` incurs any significant overhead before worrying about caching the return value. Note that it would be *incorrect* to do so if the value of `s` changes in the loop. – chepner Nov 27 '18 at 21:12
  • 1
    The obvious implication is that `s` does not change within the loop. Any run-time optimizations will make the two expressions equivalent. However, the obvious (?) answer is that you're asking the wrong entities: **time** it each way with `timeit` and see whether one is faster than the other in your application. – Prune Nov 27 '18 at 21:17
  • 2
    Premature optimization is the root of all evil... unless this is the inner loop of a time critical process you should do what is most maintainable, not what is fastest... this is evidenced by the fact that **those two don't do the same thing**: one is sensitive to length changes in the block and the other is not. – TemporalWolf Nov 27 '18 at 21:55
  • @chepner, theortically they are the same, engineeringly they are different. – Pythoner Nov 27 '18 at 22:09
  • 1
    @Pythoner Big-Oh notation is "theoretically". If you aren't talking about algorithmic complexity, then don't talk about big-oh. – juanpa.arrivillaga Nov 27 '18 at 22:11
  • @chepner no offense, how do you think to express `O(1) + O(1)` like idea? I think this is a proper/reasonable expression. – Pythoner Nov 27 '18 at 22:19
  • 1
    It is certainly not proper if by proper you mean correct. To be precise and correct, you could say something to the effect of "it has the same time complexity but a higher constant factor" – juanpa.arrivillaga Nov 27 '18 at 22:29
  • @juanpa.arrivillaga too verbose if so. – Pythoner Nov 28 '18 at 00:18

2 Answers2

7

it has to be faster.

  • Using n you're looking in the variables (dictionaries) once.
  • Using len(s) you're looking twice (len is also a function that we have to look for). Then you call the function.

That said if you do while i < n: most of the time you can get away with a classical for i in range(len(s)): loop since upper boundary doesn't change, and is evaluated once only at start in range (which may lead you to: Why wouldn't I iterate directly on the elements or use enumerate ?)

while i < len(s) allows to compare your index against a varying list. That's the whole point. If you fix the bound, it becomes less attractive.

In a for loop, it's easy to skip increments with continue (as easy as it is to forget to increment i and end up with an infinite while loop)

Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
5

You're right, here's some benchmarks:

s = np.random.rand(100)
n = 100

Above is setup.

%%timeit
50 < len(s)

86.3 ns ± 2.4 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

Versus:

%%timeit
50 < n

36.8 ns ± 1.15 ns per loop (mean ± std. dev. of 7 runs, 10000000 loops each)

But then again, it's hard to imagine differences on ~60ns level would have affected speed. Unless you're calling len(s) millions of times.

Rocky Li
  • 5,641
  • 2
  • 17
  • 33