# How to Efficiently Index PyArrays?

**URL:** <https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785>\
**Category:** Performance\
**Tags:** question, pycall, python\
**Created:** [October 14, 2021, 10:04pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785 "2021-10-14T22:04:28Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![rewindturtle](https://avatars.discourse-cdn.com/v4/letter/r/0ea827/32.png) [@rewindturtle](https://discourse.julialang.org/u/rewindturtle)\
**Post date:** [October 14, 2021, 10:04pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/1 "2021-10-14T22:04:28Z")

</div>

I have been trying to rewrite a python script I wrote a while back in julia to increase its performance. The python script used a package called gym-retro which ran a videogame emulator that the script could directly interact with. As far as I am aware, there is no Julia equivalent so I am importing gym-retro using PyCall. Game information such as the current frame and RAM are outputted as numpy arrays. My attempts to read the data from these arrays have been incredibly slow and memory inefficient. For example, if I run this code:

```julia
function index_test(pyarray::PyArray{UInt8, 3})
    a = pyarray[1, 1, 1]
end

function conversion_test(pyarray::PyArray{UInt8, 3})
    converted_frame = convert(Array{UInt8, 3}, pyarray)
end

function reset(arcade::Arcade)
    frame = pycall(arcade.env.reset, PyArray)
    println(typeof(frame))
    println(size(frame))
    @btime index_test($frame)
    @btime conversion_test($frame)
end

```

It outputs this response in the REPL:

```julia
PyArray{UInt8, 3}
(224, 240, 3)
  308.230 ns (14 allocations: 416 bytes)
  184.150 ms (5653541 allocations: 182.49 MiB)

```

I am unsure as to why indexing the array causes 14 allocations. This is bottle-necking my program as I can only process a maximum of 5 frames per second. Any advice on how I can more efficiently index data from a PyArray would be greatly appreciated.

EDIT: Here are the results if I use the `view()` function:

```julia
function view_test(pyarray::PyArray{UInt8, 3})
    a = view(pyarray, 1, 1, 1)
end

function reset(arcade::Arcade)
    frame = pycall(arcade.env.reset, PyArray)
    @btime view_test($frame)
end

```

```julia
  806.977 ns (16 allocations: 336 bytes)

```

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [October 15, 2021, 9:14pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/2 "2021-10-15T21:14:53Z")

</div>

Here is a MWE:

```julia
using BenchmarkTools
using PyCall

function index_test(pyarray::PyArray{UInt8, 3})
    s = 0
    for i in 1:size(array, 1)
        for j in 1:size(array, 2)
            for k in 1:size(array, 3)
                s += array[i, j, k]
            end
        end
    end
    s
end

function from_python(pyarray::PyArray{UInt8, 3})
    return convert(Array{UInt8, 3}, pyarray)
end

function index_test(array::Array{UInt8, 3})
    s = 0
    for i in 1:size(array, 1)
        for j in 1:size(array, 2)
            for k in 1:size(array, 3)
                s += array[i, j, k]
            end
        end
    end
    s
end

function to_python(array::Array{UInt8, 3})
    PyArray(PyObject(array))
end

array = Array{UInt8, 3}(undef, (250, 250, 3))
@btime index_test($array)
@btime to_python($array)
pyarray = PyArray(PyObject(array))
@btime index_test($pyarray)
@btime from_python($pyarray)
println()

```

with results

```julia
 89.900 μs (0 allocations: 0 bytes)
  1.440 μs (20 allocations: 1.16 KiB)
  19.330 ms (500491 allocations: 12.41 MiB)
  444.500 μs (2 allocations: 183.20 KiB)

```

So indeed, indexing into PyArray is quite slow as is the backward conversion. But I ask myself if this is really necessary, because the documentation states

> Assuming you have NumPy installed (true by default if you use Conda), then a Julia a::Array of NumPy-compatible elements is converted by PyObject(a) into a NumPy wrapper for the same data, i.e. without copying the data.

which I read as: if you call Python with `PyObject(array))` it still references `array`, i.e. changes in Python are immediately reflected in `array`. So you should be able to use Julia indexing on the passed `array` after the call.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [October 15, 2021, 9:52pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/3 "2021-10-15T21:52:20Z")

</div>

> [@rewindturtle](#):
>
> I am unsure as to why indexing the array causes 14 allocations.

Good question … as far as I can tell the `getindex` operation should completely inline to a direct pointer dereference (an `unsafe_load` on a cached pointer), and hence should be non-allocating and nearly as fast as native Julia array accesses: [https://github.com/JuliaPy/PyCall.jl/blob/8a98fb45ef39d09e11c1270e9120a32df2578d50/src/pyarray.jl#L157-L184](https://github.com/JuliaPy/PyCall.jl/blob/8a98fb45ef39d09e11c1270e9120a32df2578d50/src/pyarray.jl#L157-L184)

However, I haven’t looked at this code (written by @JobJob) for [quite some time](https://github.com/JuliaPy/PyCall.jl/pull/487), so it’s possible that some optimization is glitching. It would be worth taking a look at the generated code.

---

<div class="post-metadata">

**Author:** ![rewindturtle](https://avatars.discourse-cdn.com/v4/letter/r/0ea827/32.png) [@rewindturtle](https://discourse.julialang.org/u/rewindturtle)\
**Post date:** [October 15, 2021, 9:55pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/4 "2021-10-15T21:55:46Z")

</div>

I did a few tests earlier today and found that there are fewer allocations if the PyArray is two dimensional. I needed to convert the RGB image into grayscale anyways so flattening it into 2d with `state = pycall(np.sum, PyArray, state, axis=2)` and then indexing it brings the conversion down from 184ms to 10ms. Still a bit longer than I would like but it is definitely a big improvement.

```julia
function test(pyarray::PyArray{UInt32, 2})
    a = pyarray[1, 1]
end

function main(arcade::Arcade)
    frame = pycall(arcade.env.reset, PyArray)
    frame = pycall(np.sum, PyArray, frame, axis=2)
    println(typeof(frame))
    println(size(frame))
    @btime test($frame)
end

```

```julia
PyArray{UInt32, 2}
(224, 240)
  218.672 ns (9 allocations: 272 bytes)

```

---

<div class="post-metadata">

**Author:** ![rewindturtle](https://avatars.discourse-cdn.com/v4/letter/r/0ea827/32.png) [@rewindturtle](https://discourse.julialang.org/u/rewindturtle)\
**Post date:** [October 15, 2021, 10:10pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/5 "2021-10-15T22:10:36Z")

</div>

Could you elaborate a bit more on how to pass a Julia array into numpy?

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [October 15, 2021, 10:27pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/6 "2021-10-15T22:27:28Z")

</div>

Just checked my understanding of the documentation: we pass arrays by reference to python. Modified example from [this thread](https://discourse.julialang.org/t/passing-numpy-arrays-between-python-and-julia/25826/3)

```julia
using PyCall

py"""
import numpy
xs = numpy.zeros((2, 2))
"""

xs = PyArray(py"xs"o)
println(xs)

py"""
import numpy
xs[0, 0] = 1
"""

println(xs)

```

resolves to

```julia
[0.0 0.0; 0.0 0.0]
[1.0 0.0; 0.0 0.0]

```

But of course you are out of luck if Python generates the array.

---

<div class="post-metadata">

**Author:** ![rewindturtle](https://avatars.discourse-cdn.com/v4/letter/r/0ea827/32.png) [@rewindturtle](https://discourse.julialang.org/u/rewindturtle)\
**Post date:** [October 15, 2021, 10:34pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/7 "2021-10-15T22:34:59Z")

</div>

Oh I see. Thank you for the clarification. Unfortunately Python does generate my array. ☹

---

<div class="post-metadata">

**Author:** ![rewindturtle](https://avatars.discourse-cdn.com/v4/letter/r/0ea827/32.png) [@rewindturtle](https://discourse.julialang.org/u/rewindturtle)\
**Post date:** [October 15, 2021, 10:50pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/8 "2021-10-15T22:50:10Z")

</div>

Here is the llvm of the following code:

```julia
function test(pyarray::PyArray{UInt8, 3})
    a = pyarray[1, 1, 1]
end

function main(arcade::Arcade)
    frame = pycall(arcade.env.reset, PyArray)
    println(typeof(frame))
    println(size(frame))
    @code_llvm test(frame)
end

```

```julia
PyArray{UInt8, 3}
(224, 240, 3)

; @ C:\Users\user\PycharmProjects\juliaProject\arcade.jl:145 within `test'
; Function Attrs: uwtable
define i8 @julia_test_3329({}* nonnull align 8 dereferenceable(80) %0) #0 {
top:
; @ C:\Users\user\PycharmProjects\juliaProject\arcade.jl:146 within `test'
  %1 = call i8 @j_getindex_3331({}* nonnull %0, i64 signext 1, i64 signext 1, i64 signext 1) #0
  ret i8 %1
}

```

Here is the assembly code:

```julia
	.text
; ┌ @ arcade.jl:145 within `test'
	pushq	%rbp
	movq	%rsp, %rbp
	subq	$32, %rsp
; │ @ arcade.jl:146 within `test'
	movabsq	$getindex, %rax
	movl	$1, %edx
	movl	$1, %r8d
	movl	$1, %r9d
	callq	*%rax
	addq	$32, %rsp
	popq	%rbp
	retq
	nopl	(%rax,%rax)
; └

```

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [October 15, 2021, 10:50pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/9 "2021-10-15T22:50:22Z")

</div>

Just for completeness sake: I profiled the MWE. `from_python` looks OK to me. `index_test` shows this picture:

 ![image](https://global.discourse-cdn.com/julialang/original/3X/6/a/6a9666671e13ec3d06a671c29a561a48665f9968.png)

So I can’t even say which PyCall function is the culprit.

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [October 15, 2021, 10:53pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/10 "2021-10-15T22:53:01Z")

</div>

So your option would be to convert first and then index in Julia? At least you should get more than 5 frames this way.

---

<div class="post-metadata">

**Author:** ![rewindturtle](https://avatars.discourse-cdn.com/v4/letter/r/0ea827/32.png) [@rewindturtle](https://discourse.julialang.org/u/rewindturtle)\
**Post date:** [October 15, 2021, 10:59pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/11 "2021-10-15T22:59:17Z")

</div>

Thank you for your help. As I need to convert to grayscale, crop, and downsample the frame the fastest implementation I could find was the following:

```julia
function format_state(state::PyArray{UInt32, 2})
    new_state = zeros(Float32, (92, 120))
    @simd for i in 1:92
        i2 = 2 * i + 25
        @simd for j in 1:120
            j2 = 2 * j
            new_state[i, j] = (Float32(state[i2-1, j2-1]) + Float32(state[i2, j2-1]) +
                               Float32(state[i2-1, j2]) + Float32(state[i2, j2])) / 3060.0
        end
    end
    return new_state
end

function main(arcade::Arcade)
    state = pycall(arcade.env.reset, PyArray)
    state = pycall(np.sum, PyArray, state, axis=2)
    formatted_state = format_state(state)
end

```

The full conversion of a single frame is just under 10 ms so I can now process 100 frames per second.

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [October 15, 2021, 11:07pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/12 "2021-10-15T23:07:50Z")

</div>

> [@goerch](#):
>
> But of course you are out of luck if Python generates the array.

No, that is what PyArray is for — it exposes a copy-free `AbstractArray` wrapper for a numpy array.

---

<div class="post-metadata">

**Author:** ![goerch](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/goerch/32/29122_2.png) [@goerch](https://discourse.julialang.org/u/goerch)\
**Post date:** [October 15, 2021, 11:09pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/13 "2021-10-15T23:09:06Z")

</div>

MWE

```julia
using PyCall

function index_test(pyarray::PyArray{UInt8, 3})
    s = 0
    for i in 1:size(array, 1)
        for j in 1:size(array, 2)
            for k in 1:size(array, 3)
                s += array[i, j, k]
            end
        end
    end
    s
end

array = Array{UInt8, 3}(undef, (250, 250, 3))
pyarray = PyArray(PyObject(array))
@code_warntype index_test(pyarray)

```

outputs

```julia
Variables
  #self#::Core.Const(index_test)
  pyarray::PyArray{UInt8, 3}
  @_3::Any
  s::Any
  @_5::Any
  i::Any
  @_7::Any
  j::Any
  k::Any

Body::Any
1 ── (s = 0)
│ %2 = Main.size(Main.array, 1)::Any
│ %3 = (1:%2)::Any
│ (@_3 = Base.iterate(%3))
│ %5 = (@_3 === nothing)::Bool
│ %6 = Base.not_int(%5)::Bool
└─── goto #10 if not %6
2 ┄─ %8 = @_3::Any
│ (i = Core.getfield(%8, 1))
│ %10 = Core.getfield(%8, 2)::Any
│ %11 = Main.size(Main.array, 2)::Any
│ %12 = (1:%11)::Any
│ (@_5 = Base.iterate(%12))
│ %14 = (@_5 === nothing)::Bool
│ %15 = Base.not_int(%14)::Bool
└─── goto #8 if not %15
3 ┄─ %17 = @_5::Any
│ (j = Core.getfield(%17, 1))
│ %19 = Core.getfield(%17, 2)::Any
│ %20 = Main.size(Main.array, 3)::Any
│ %21 = (1:%20)::Any
│ (@_7 = Base.iterate(%21))
│ %23 = (@_7 === nothing)::Bool
│ %24 = Base.not_int(%23)::Bool
└─── goto #6 if not %24
4 ┄─ %26 = @_7::Any
│ (k = Core.getfield(%26, 1))
│ %28 = Core.getfield(%26, 2)::Any
│ %29 = s::Any
│ %30 = Base.getindex(Main.array, i, j, k)::Any
│ (s = %29 + %30)
│ (@_7 = Base.iterate(%21, %28))
│ %33 = (@_7 === nothing)::Bool
│ %34 = Base.not_int(%33)::Bool
└─── goto #6 if not %34
5 ── goto #4
6 ┄─ (@_5 = Base.iterate(%12, %19))
│ %38 = (@_5 === nothing)::Bool
│ %39 = Base.not_int(%38)::Bool
└─── goto #8 if not %39
7 ── goto #3
8 ┄─ (@_3 = Base.iterate(%3, %10))
│ %43 = (@_3 === nothing)::Bool
│ %44 = Base.not_int(%43)::Bool
└─── goto #10 if not %44
9 ── goto #2
10 ┄ return s

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [October 15, 2021, 11:09pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/14 "2021-10-15T23:09:10Z")

</div>

> [@rewindturtle](#):
>
> Here is the assembly code:

Not helpful since it looks like `getindex` is not inlined, so you can’t see what it is doing. Maybe add `@inbounds`?

---

<div class="post-metadata">

**Author:** ![rewindturtle](https://avatars.discourse-cdn.com/v4/letter/r/0ea827/32.png) [@rewindturtle](https://discourse.julialang.org/u/rewindturtle)\
**Post date:** [October 15, 2021, 11:17pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/15 "2021-10-15T23:17:02Z")

</div>

Sure thing

```julia
function test(pyarray::PyArray{UInt8, 3})
    a = pyarray[1, 1, 1]
end

function main(arcade::Arcade)
    state = pycall(arcade.env.reset, PyArray)
    @code_native @inbounds test(state)
end

```

```julia
	.text
	.file	"@inbounds"
	.globl	julia_@inbounds_2913 # -- Begin function julia_@inbounds_2913
	.p2align	4, 0x90
	.type	julia_@inbounds_2913,@function
julia_@inbounds_2913: # @"julia_@inbounds_2913"
	.cfi_startproc
# %bb.0: # %top
	pushq	%rbp
	.cfi_def_cfa_offset 16
	.cfi_offset %rbp, -16
	movq	%rsp, %rbp
	.cfi_def_cfa_register %rbp
	pushq	%r14
	pushq	%rsi
	pushq	%rdi
	pushq	%rbx
	andq	$-32, %rsp
	subq	$160, %rsp
	.cfi_offset %rbx, -48
	.cfi_offset %rdi, -40
	.cfi_offset %rsi, -32
	.cfi_offset %r14, -24
	movq	%r8, %rsi
	vxorps	%xmm0, %xmm0, %xmm0
	vmovaps	%ymm0, 96(%rsp)
	movq	$0, 128(%rsp)
	movl	$41024112, %eax # imm = 0x271FA70
	vzeroupper
	callq	*%rax
	movq	%rax, %r14
	movq	$12, 96(%rsp)
	movq	(%r14), %rax
	movq	%rax, 104(%rsp)
	leaq	96(%rsp), %rax
	movq	%rax, (%r14)
	movq	$243776616, 56(%rsp) # imm = 0xE87BC68
	movq	$1802904512, 64(%rsp) # imm = 0x6B7623C0
	movabsq	$j1_Expr_2915, %rax
	leaq	56(%rsp), %rdi
	movl	$1802224016, %ecx # imm = 0x6B6BC190
	movq	%rdi, %rdx
	movl	$2, %r8d
	callq	*%rax
	movq	%rax, %rbx
	movq	%rbx, 120(%rsp)
	movq	%rsi, 56(%rsp)
	movabsq	$j1_esc_2916, %rax
	movl	$1832004368, %ecx # imm = 0x6D322B10
	movq	%rdi, %rdx
	movl	$1, %r8d
	callq	*%rax
	movq	%rax, 112(%rsp)
	movq	$243260656, 56(%rsp) # imm = 0xE7FDCF0
	movq	$243314000, 64(%rsp) # imm = 0xE80AD50
	movq	%rax, 72(%rsp)
	movabsq	$j1_Expr_2917, %rax
	movl	$1802224016, %ecx # imm = 0x6B6BC190
	movq	%rdi, %rdx
	movl	$3, %r8d
	callq	*%rax
	movq	%rax, 112(%rsp)
	movq	$243838488, 56(%rsp) # imm = 0xE88AE18
	movq	%rax, 64(%rsp)
	movabsq	$j1_Expr_2918, %rax
	movl	$1802224016, %ecx # imm = 0x6B6BC190
	movq	%rdi, %rdx
	movl	$2, %r8d
	callq	*%rax
	movq	%rax, %rsi
	movq	%rsi, 128(%rsp)
	movq	$243776616, 56(%rsp) # imm = 0xE87BC68
	movq	$244007064, 64(%rsp) # imm = 0xE8B4098
	movabsq	$j1_Expr_2919, %rax
	movl	$1802224016, %ecx # imm = 0x6B6BC190
	movq	%rdi, %rdx
	movl	$2, %r8d
	callq	*%rax
	movq	%rax, 112(%rsp)
	movq	$243513968, 56(%rsp) # imm = 0xE83BA70
	movq	%rbx, 64(%rsp)
	movq	%rsi, 72(%rsp)
	movq	%rax, 80(%rsp)
	movq	$243314000, 88(%rsp) # imm = 0xE80AD50
	movabsq	$j1_Expr_2920, %rax
	movl	$1802224016, %ecx # imm = 0x6B6BC190
	movq	%rdi, %rdx
	movl	$5, %r8d
	callq	*%rax
	movq	104(%rsp), %rcx
	movq	%rcx, (%r14)
	leaq	-32(%rbp), %rsp
	popq	%rbx
	popq	%rdi
	popq	%rsi
	popq	%r14
	popq	%rbp
	retq
.Lfunc_end0:
	.size	julia_@inbounds_2913, .Lfunc_end0-julia_@inbounds_2913
	.cfi_endproc
                                        # -- End function
	.section	".note.GNU-stack","",@progbits

```

---

<div class="post-metadata">

**Author:** ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)\
**Post date:** [October 15, 2021, 11:17pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/16 "2021-10-15T23:17:57Z")

</div>

(`@code_llvm` or `@code_lowered` or `@code_warntype` are much more readable than `@code_native`) … I would also suggest putting `@inbounds` inside `test` rather than at the call site.

---

<div class="post-metadata">

**Author:** ![rewindturtle](https://avatars.discourse-cdn.com/v4/letter/r/0ea827/32.png) [@rewindturtle](https://discourse.julialang.org/u/rewindturtle)\
**Post date:** [October 15, 2021, 11:20pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/17 "2021-10-15T23:20:23Z")

</div>

Sorry about that.

```julia
function test(pyarray::PyArray{UInt8, 3})
    @inbounds a = pyarray[1, 1, 1]
end

function main(arcade::Arcade)
    state = pycall(arcade.env.reset, PyArray)
    @code_llvm test(state)
end

```

```julia
; @ C:\Users\user\PycharmProjects\juliaProject\arcade.jl:159 within `test'
; Function Attrs: uwtable
define i8 @julia_test_2994({}* nonnull align 8 dereferenceable(80) %0) #0 {
top:
; @ C:\Users\user\PycharmProjects\juliaProject\arcade.jl:160 within `test'
  %1 = call i8 @j_getindex_2996({}* nonnull %0, i64 signext 1, i64 signext 1, i64 signext 1) #0
  ret i8 %1
}

```

```julia
"C:\Users\user\AppData\Local\Programs\Julia-1.6.3\bin\julia.exe" --check-bounds=no --history-file=no --inline=no --color=yes --math-mode=ieee --handle-signals=no --startup-file=yes --compile=yes --depwarn=yes --code-coverage=none --track-allocation=none "C:/Users/user/PycharmProjects/juliaProject/arcade.jl"
Variables
  #self#::Core.Const(test)
  pyarray::PyArray{UInt8, 3}
  val::UInt8
  a::UInt8

Body::UInt8
1 ─ $(Expr(:inbounds, true))
│ %2 = Base.getindex(pyarray, 1, 1, 1)::UInt8
│ (a = %2)
│ (val = %2)
│ $(Expr(:inbounds, :pop))
└── return val

```

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [October 15, 2021, 11:33pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/18 "2021-10-15T23:33:27Z")

</div>

> [@rewindturtle](#):
>
> `new_state = zeros(Float32, (92, 120))`

Since you overwrite this, it’s more efficient to do

```julia
new_state = Vector{Float32}(undef, 92, 120))

```

---

<div class="post-metadata">

**Author:** ![rewindturtle](https://avatars.discourse-cdn.com/v4/letter/r/0ea827/32.png) [@rewindturtle](https://discourse.julialang.org/u/rewindturtle)\
**Post date:** [October 15, 2021, 11:35pm UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/19 "2021-10-15T23:35:52Z")

</div>

I did test this. I found the latter to actually be faster. 🤷‍♀️

---

<div class="post-metadata">

**Author:** ![DNF](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dnf/32/10191_2.png) [@DNF](https://discourse.julialang.org/u/DNF)\
**Post date:** [October 16, 2021, 7:23am UTC](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785/20 "2021-10-16T07:23:43Z")

</div>

That would be expected. But I’m getting the impression you mean the opposite, which would be highly surprising.

[Next page](https://discourse.julialang.org/t/how-to-efficiently-index-pyarrays/69785.md?page=2)
