Указатели и «Хранение небезопасной производной C от временной ссылки на Python»

Я писал код для хранения (потенциально) очень большого целочисленного значения в массив chars ссылается указатель. Мой код выглядит так:

 cdef class Variable: cdef unsigned int Length cdef char * Array def __cinit__(self, var, length): self.Length = length self.Array = <char *>malloc(self.Length * sizeof(char)) # Error for i in range(self.Length): self.Array[i] = <char>(var >> (8 * i)) def __dealloc__(self): self.Array = NULL 

Когда я попытался скомпилировать код, я получил сообщение об ошибке «Хранение небезопасной производной C от временной ссылки Python» в комментариях. Мой вопрос таков: какую временную ссылку на Python я получаю на C и храня, и как ее исправить?

2 Solutions collect form web for “Указатели и «Хранение небезопасной производной C от временной ссылки на Python»”

Проблема заключается в том, что под капотом создается временная переменная для хранения массива до назначения для self.Array и он не будет действителен после выхода метода.

Обратите внимание, что в документации рекомендуется:

функции C-API для выделения памяти в куче Python обычно предпочтительнее описанных выше низкоуровневых C-функций, поскольку память, которую они предоставляют, фактически учитывается в системе управления внутренней памятью Python. Они также имеют специальную оптимизацию для небольших блоков памяти, что ускоряет их распределение, избегая дорогостоящих вызовов операционной системы.

Соответственно, вы можете написать, как показано ниже, что, по-видимому, подходит для использования в этом случае:

 from cpython.mem cimport PyMem_Malloc, PyMem_Realloc, PyMem_Free cdef class Variable: cdef unsigned int Length cdef char * Array def __cinit__(self, var,size_t length): self.Length = length self.Array = <char *>PyMem_Malloc(length * sizeof(char)) #as in docs, a good practice if not self.Array: raise MemoryError() for i in range(self.Length): self.Array[i] = <char>(var >> (8 * i)) def __dealloc__(self): PyMem_Free(self.Array) 

Ответ @ rll делает довольно хорошую работу по очистке кода и «все делает правильно» (самое главное, освобождение памяти, которое отсутствовало в __dealloc__ в вопросе!).

Фактическая проблема, вызывающая ошибку, заключается в том, что вы не cimport malloc cimport . Из-за этого Cython предполагает, что malloc – это функция Python, возвращающая объект Python, который вы хотите передать в char* . В верхней части файла добавьте

 from libc.stdlib cimport malloc, free 

и это сработает. Или, альтернативно, используйте PyMem_Malloc (cimporting it), как это делает @rll, и это тоже сработает.

  • Компилятор не может найти Py_InitModule () .. он устарел, и если да, то что я должен использовать?
  • Правильная циклическая сборка мусора в модулях расширения
  • Учебники по оптимизации нетривиальных приложений Python с расширениями C или Cython
  • Как я могу написать функцию C, которая принимает либо int, либо float?
  • Определение PyBufferProcs в Python 2.7, когда класс реализует PEP 3118
  • Что делает Cython с импортом?
  • Как указать docstring для __init__ в расширении Python C
  • Интеграция C и Python: ValueError: функции модуля не могут устанавливать METH_CLASS или METH_STATIC
  • Python - лучший язык программирования в мире.