在 Julia 中使用 PyCall.jl 时修改 Python 对象的属性

Modify a Python object's attribute when using PyCall.jl in Julia

我正在尝试通过 PyCall.jl 与 python 库进行交互,其中库 returns 具有我想要的属性的 python 对象(Julia 中的 PyObject)在 Julia 中修改。例如说我有以下虚拟 python class,

import numpy as np

class MyNumpy:
     def __init__(self,n,m):
          self.array = np.zeros((n,m))
          self.size = (n,m)

现在在 Julia 中,我使用 PyCall.jl 加载这个 python class 并实例化,例如:

using PyCall

mynumpy = pyimport("MyNumpy.MyNumpy")
pyobject = mynumpy(3,3)
...

> pyobject.array
> 3×3 Array{Float64,2}:
  0.0  0.0  0.0
  0.0  0.0  0.0
  0.0  0.0  0.0
...

pyobject.array[1,1] = 1.0 

> pyobject.array
> 3×3 Array{Float64,2}:
  0.0  0.0  0.0
  0.0  0.0  0.0
  0.0  0.0  0.0

最后一行代码执行没有任何错误,但是在调查 pyobject.array[1,1] 后,该值没有改变(即保持为 0.0)。

如何在 Julia 中更改 Pycall.jl PyObject 属性值,例如,我可以使用指针来执行此操作吗?如果可以,怎么做? 抱歉,如果这是很明显,但我运气不好,无法使用 PyCall.jl 文档弄清楚如何做到这一点。提前致谢。

P.S。实际的 python 库不是可以轻易修改的东西。

PyCall 默认将对象转换为 Julia 类型(如果它们适当地发出嘎嘎声)。在这种情况下,当您访问 MyNumpy class 的 array 字段时,就会发生这种情况:它 returns 是一个 numpy 数组,PyCall 会将其转换为 Julian [=14] =] 在边界处。如果您想选择退出该自动转换,您可以使用 uglier, dot-access with a string:

julia> py"""
       import numpy as np

       class MyNumpy:
            def __init__(self,n,m):
                 self.array = np.zeros((n,m))
                 self.size = (n,m)
       """

julia> mynumpy = py"MyNumpy"
PyObject <class '__main__.MyNumpy'>

julia> pyobject = mynumpy(3,3)
PyObject <__main__.MyNumpy object at 0x1383398d0>

julia> pyobject.array # converted (copied!) into a Julian Array
3×3 Array{Float64,2}:
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0

julia> pyobject."array" # This is the "raw" numpy array!
PyObject array([[0., 0., 0.],
       [0., 0., 0.],
       [0., 0., 0.]])

现在,您可以在 Python 的列表列表表示中工作,但这很烦人; API 不是最好的,您必须记住基于 0 的行主要实现。 PyCall 有一个很好、方便的助手,它通过 Julian AbstractArray:

将数组公开为共享内存
julia> array = PyArray(pyobject."array")
3×3 PyArray{Float64,2}:
 0.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0

julia> array[1,1] = 1.0
1.0

julia> array
3×3 PyArray{Float64,2}:
 1.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0

julia> pyobject.array # remember, this is a copy
3×3 Array{Float64,2}:
 1.0  0.0  0.0
 0.0  0.0  0.0
 0.0  0.0  0.0