# Structured array in PyCall

**URL:** <https://discourse.julialang.org/t/structured-array-in-pycall/21118>\
**Category:** General Usage\
**Created:** [February 23, 2019, 5:36pm UTC](https://discourse.julialang.org/t/structured-array-in-pycall/21118 "2019-02-23T17:36:08Z")\
**Posts on this page:** 2\
**Page:** 1

<div class="post-metadata">

**Author:** ![aplavin](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/aplavin/32/222056_2.png) [@aplavin](https://discourse.julialang.org/u/aplavin)\
**Post date:** [February 23, 2019, 5:36pm UTC](https://discourse.julialang.org/t/structured-array-in-pycall/21118/1 "2019-02-23T17:36:08Z")

</div>

I need to interface with a Python API which returns a structured array. Currently PyCall just returns `PyObject array(..., dtype=...)`. Is it reasonably possible to convert it to some Julia-native format, like array of namedtuples or similar?

Simple example:

```julia
using PyCall
py"np.array([('Rex', 9, 81.0), ('Fido', 3, 27.0)], dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')])"
# gives PyObject array([('Rex', 9, 81.), ('Fido', 3, 27.)], dtype=[('name', '<U10'), ('age', '<i4'), ('weight', '<f4')])

```

---

<div class="post-metadata">

**Author:** ![tkf](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tkf/32/17635_2.png) [@tkf](https://discourse.julialang.org/u/tkf)\
**Post date:** [February 24, 2019, 10:38am UTC](https://discourse.julialang.org/t/structured-array-in-pycall/21118/2 "2019-02-24T10:38:47Z")

</div>

I don’t think PyCall directly supports it. But you can manually load the data as an array-of-(named)tuples.

```julia
julia> py"""
       import numpy
       a = numpy.array([('Rex', 9, 81.0), ('Fido', 3, 27.0)], dtype=[('name', 'U10'), ('age', 'i4'), ('weight', 'f4')])
       """

julia> p = py"a.ctypes.data"
93965367751616

julia> a = unsafe_wrap(Array, Ptr{NamedTuple{(:name, :age, :weight), Tuple{NTuple{10, UInt32}, Int32, Float32}}}(p), 2)
2-element Array{NamedTuple{(:name, :age, :weight),Tuple{NTuple{10,UInt32},Int32,Float32}},1}:
 (name = (0x00000052, 0x00000065, 0x00000078, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), age = 9, weight = 81.0)
 (name = (0x00000046, 0x00000069, 0x00000064, 0x0000006f, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), age = 3, weight = 27.0)

julia> a[1]
(name = (0x00000052, 0x00000065, 0x00000078, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000), age = 9, weight = 81.0f0)

julia> a[1].age
9

julia> a[2].weight
27.0f0

julia> s = transcode(String, collect(a[1].name))
"Rex\0\0\0\0\0\0\0"

julia> s[1:first(findfirst("\0", s))-1] # maybe there is a better way?
"Rex"

```

If you are going this way, have a look at `unsafe_wrap` documentation and understand the caveats.
