0

I have some stupid questions about the efficiency in Python:

  1. Is it more efficient if I assigned array[x][y] to a (e.g. a=array[x][y]) or is it better to use array[x][y] directly?
  2. For some operations in Python, would it be more efficient if I put them in one single function?
sophros
  • 14,672
  • 11
  • 46
  • 75
Victor. L
  • 145
  • 2
  • 9
  • What use cases does this apply? Please include a [minimal and verifiable](https://stackoverflow.com/help/mcve) example – Jab Jan 18 '19 at 21:22
  • 1
    They're not strictly the same, if `array` is being changed by another thread. Making a local copy is likely to be very slightly more efficient if you're using it more than a couple times. – Max Jan 18 '19 at 21:23
  • 1. If you are going to use it more than once. 2. Function calls have a cost if they didn't inlining wouldn't be needed. – Dan D. Jan 18 '19 at 21:25
  • @DanD. - how do you imagine inlining to work for Python? – sophros Jan 18 '19 at 21:27
  • @sophros There is a paper on it. For CPython, the idea was to recover the CFG from the byte code and then merge the CFGs (this can turn returns in the inlined function into gotos) and then generate byte code. It can be done. PyPy might already do it in its JIT. But it can also be done manually. All the optimizations and refactorings can. – Dan D. Jan 18 '19 at 21:33
  • @DanD. could you please reference the paper? I would love to read it. – sophros Jan 18 '19 at 21:34
  • @Jaba Will different cases make different? In my understanding, the only cases' difference made is by the number of data. – Victor. L Jan 18 '19 at 21:39
  • @sophros The Effect of Unrolling and Inlining for Python Bytecode Optimizations (Asher and Rotem) – Dan D. Jan 18 '19 at 21:39

2 Answers2

1

The difference in the performance comes from the implicit use of indexing operator and accessing the y-th value of x-th "column" of the array. Once you assign a (a = array[x][y]) there is no need for these operations to be performed to get the actual value in array[x][y] - it is readily available in a.

The exact differences on performance depend on the implementation. In case of NumPy the performance of array[x][y] would be far better than in case of native python lists thanks to the implementation fine-tuned for uniform-type arrays and continuous block of memory allocation.

I recommend that you time the actual use to see the impact in your particular case.

sophros
  • 14,672
  • 11
  • 46
  • 75
0

Let's find out:

In [8]: def with_assignment(arr, x, y):
   ...:     a = arr[x][y]
   ...:     return a
   ...: 

In [9]: dis.dis(with_assignment)
  2           0 LOAD_FAST                0 (arr)
              3 LOAD_FAST                1 (x)
              6 BINARY_SUBSCR       
              7 LOAD_FAST                2 (y)
             10 BINARY_SUBSCR       
             11 STORE_FAST               3 (a)

  3          14 LOAD_FAST                3 (a)
             17 RETURN_VALUE        

In [10]: def without_assignment(arr, x, y):
   ....:     return arr[x][y]
   ....: 

In [11]: dis.dis(without_assignment)
  2           0 LOAD_FAST                0 (arr)
              3 LOAD_FAST                1 (x)
              6 BINARY_SUBSCR       
              7 LOAD_FAST                2 (y)
             10 BINARY_SUBSCR       
             11 RETURN_VALUE        

So adding the assignment adds two bytecode instructions, a STORE_FAST and LOAD_FAST. So, strictly speaking, using the value directly is faster. But by how much?

In [34]: arr = [range(100) for _ in xrange(1000)]

In [35]: %timeit without_assignment(arr, random.randint(0,999), random.randint(0,99))
The slowest run took 9.75 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 1.83 µs per loop

In [36]: %timeit with_assignment(arr, random.randint(0,999), random.randint(0,99))
The slowest run took 10.57 times longer than the fastest. This could mean that an intermediate result is being cached.
1000000 loops, best of 3: 1.8 µs per loop

So, for relatively small arrays it seems like the difference is a few microseconds. If you're trying to make your code more efficient, this probably isn't the bottleneck.

If you're going to reuse the value, obviously store it so you don't have to recalculate it.

munk
  • 12,340
  • 8
  • 51
  • 71