Изменить атрибут объекта Python при использовании PyCall.jl в Julia - PullRequest
2 голосов
/ 04 ноября 2019

Я пытаюсь взаимодействовать с библиотекой python через PyCall.jl, где библиотека возвращает объект python (PyObject в Julia) с атрибутами, которые я хочу изменить в Julia. Например, скажем, у меня есть следующий фиктивный класс Python,

import numpy as np

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

Теперь в Джулии я загружаю этот класс Python, используя PyCall.jl и instantiate, что-то вроде:

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).

Как можно было бы изменить значение атрибута PyCall.jl PyObject в JuliaНапример, могу ли я использовать указатели для этого, если да, то как? Извините, если это очевидно, но мне не повезло, и я не могу понять, как это сделать, используя документацию PyCall.jl. Заранее спасибо.

PS Настоящая библиотека python - это не то, что можно легко изменить.

1 Ответ

2 голосов
/ 04 ноября 2019

PyCall по умолчанию конвертирует объекты в типы Julia, если они крякают соответствующим образом. В этом случае это происходит, когда вы обращаетесь к полю array вашего класса MyNumpy: он возвращает пустой массив, который PyCall преобразует в юлианский Array на границе. Если вы хотите отказаться от этого автоконвертации, вы можете использовать более точный точечный доступ со строкой :

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 не самый лучший, и вы должны помнить реализацию, основанную на нулях, на основе строк. 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
...