PyCall: Modifying an array in Python

pycall

#1

I ran into a problem that is reproduced with the following elementary snippet:

app = pyeval("lambda x: x.append(1)")
x = []
app(x)
@show x
#  x = Any[]

Why is x not modified?

I am guessing that append creates a new block of data for the python object while Julia only keeps track of the original data? Can this be fixed?


#2

Right, the argument x is converted to a Python representation using PyObject(x), which makes a copy (because Python does not know how to use a Julia Any array – the underlying memory representations are different). This object is passed to the closure, appended-to, and promptly forgotten.

However, there are several object types which do have transparent sharing: PyVector, and typed arrays (which will be converted to numpy arrays on the Python side, pointing to the same memory location as in Julia).

e.g. PyVector:

julia> x = PyVector([1,2,3])
...
julia> app(x)

julia> x
4-element Int64 PyVector:
 1
 2
 3
 1

#3

Thank you for this. That works for me now. But one thing I don’t understand yet:

app = pyeval("lambda x: x.append(1)")
x = Float64[] 
app(x)

throws an error

ERROR: PyError (:PyObject_Call) <type 'exceptions.AttributeError'>
AttributeError("'numpy.ndarray' object has no attribute 'append'",)
  File "PyCall.jl", line 1, in <lambda>

But doesn’t PyVector(x) convert to a numpy array as well? What is the difference?


#4

No, it’s a wrapper of a Python list:


#5

ah - thanks, I never noticed that PyVector and PyArray are quite different.