Python перебирает динамически выделенный массив Cython

Я пишу оболочку Python для класса C и выделяю память с помощью PyMem_Malloc, как описано здесь

cdef class SomeMemory:

    cdef double* data

    def __cinit__(self, size_t number):
        # allocate some memory (uninitialised, may contain arbitrary data)
        self.data = <my_data_t*> PyMem_Malloc(number * sizeof(my_data_t))
        if not self.data:
            raise MemoryError()

Затем я импортирую и использую класс в другом скрипте, используя:

import SomeMemory

sm = SomeMemory(10)

Теперь я хотел бы получить доступ к элементам self.data, но столкнулся с двумя проблемами.

  1. если я наберу self.data и нажму Enter, ядро ​​​​ipython выйдет из строя
  2. если я попытаюсь зациклиться на собственных данных

как:

for p in self.data:
    print p

Я получаю сообщение об ошибке, что self.data не является итерируемым.

Как я могу получить доступ к self.data? Нужно ли мне сначала преобразовать элементы в my_data_t?


person Fra    schedule 20.03.2015    source источник


Ответы (1)


(Сильно отредактировано в свете обновленного вопроса)

Итак, насколько я понимаю, self.data необходимо объявить общедоступным для доступа к нему из Python:

cdef class SomeMemory:   
    cdef public double* data
    # also make sure you define __dealloc__ to remove the data

Однако, похоже, здесь это не соблюдается.

Однако ваши настоящие проблемы заключаются в том, что Python не знает, что делать с объектом типа double *. Это, конечно, никогда не будет итерируемым, потому что информация о том, когда остановиться, просто не сохраняется (поэтому она всегда будет идти с конца.

Есть ряд лучших альтернатив:

  • вы храните свои данные в виде массива Python (см. http://docs.cython.org/src/tutorial/array.html для руководства). У вас есть быстрый доступ к необработанному указателю c из Cython, если хотите, но также Python знает, что с ним делать.

Код следует

from cpython cimport array as c_array
from array import array

cdef class SomeMemory:
   cdef c_array.array data

   def __cinit__(self, size_t number):
      self.data = array('d', some initial value goes here)
  • Вы храните свои данные в виде массива numpy. Это, возможно, немного сложнее, но имеет те же преимущества. Пример приводить не буду, проще найти.

  • Вы используете типизированное представление памяти Cython: http://docs.cython.org/src/userguide/memoryviews.html. Преимущество этого в том, что вы можете самостоятельно контролировать управление памятью (если это абсолютно важно для вас). Однако я не уверен на 100%, что вы можете получить к ним чистый доступ в Python (лень тестировать!)

  • Вы оборачиваете данные в свой собственный класс, реализующий __getitem__ и __len__, чтобы их можно было использовать в качестве итератора. Это, вероятно, больше проблем, чем оно того стоит.

Я рекомендую первый вариант, если у вас нет веских оснований для одного из других.

person DavidW    schedule 20.03.2015
comment
извините, я плохо объяснил. Я хотел сказать, что атрибут self.data не виден снаружи - person Fra; 21.03.2015
comment
Я изменил свой ответ, чтобы он соответствовал измененному вопросу... Надеюсь, теперь он более полезен. - person DavidW; 21.03.2015
comment
Большое спасибо за длинное объяснение! - person Fra; 24.03.2015
comment
Я не знал об объявлении self.data общедоступным, что решит часть проблемы. Спасибо! Что касается вашего второго момента, я не могу просто использовать массив Python, потому что my_data_t на самом деле является структурой в моем коде C, а не стандартным типом данных. Я предполагаю, что реализация оболочки класса - единственный вариант в этом случае? - person Fra; 24.03.2015
comment
(Удалено несколько неправильных комментариев.) Да, похоже, вам нужно будет реализовать небольшой класс-оболочку, содержащий основные функции итерации. [Я думаю, что представления памяти весьма ограничены в отношении того, какие типы они могут принимать.] - person DavidW; 24.03.2015