es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

Función Cython que genera un fallo de segmentación al llamar desde Python

Así que estoy intentando hacer un script que clonará algunos valores en una matriz 2D y dado que la matriz puede ser enorme, estoy utilizando cython, por cierto, soy nuevo en cython. Aquí está el código

from cpython cimport *

def cloningNodes(matrix,toClone):
    cdef Py_ssize_t matrixSize=PyList_Size(matrix),cloneSize=PyList_Size(toClone),newSize=matrixSize+cloneSize,i,j
    output=PyList_New(newSize)
    for i in range(matrixSize):
        PyList_SET_ITEM(output,i,
            <object>PyList_GET_ITEM(matrix,i))
        for j in range(cloneSize):
            currentRow=<object>PyList_GET_ITEM(output,i)
            PyList_Append(currentRow,<object>PyList_GET_ITEM(
                    <object>PyList_GET_ITEM(matrix,i),PyLong_AsSsize_t(<object>PyList_GET_ITEM(toClone,j))
                )
            )
    for i in range(cloneSize):
        PyList_SET_ITEM(output,i+matrixSize,<object>PyList_GET_ITEM(output,PyLong_AsSsize_t(<object>PyList_GET_ITEM(toClone,i))))
    return output

Después de compilar y llamar a este módulo con

from MODULE_NAME import cloningNodes
cloningNodes([[1,2],[2,1]],[1])

Me está dando una falla de segmentación (CoreDumped). ¿Alguien puede decirme por qué está dando una falla de segmentación junto con cualquier mejora menor que pudiera encontrar?
Edit: Por cierto, intenté poner una declaración de impresión antes de return output y parece que la lista se crea sin problemas, pero hay algún problema al devolver la lista.

Tags:  , ,

Answer

  1. Avatar for davy.ai

    El código parece tener algunos problemas que pueden causar un fallo de segmentación. Aquí hay algunas sugerencias para mejorar el código:

    1. Para clonar una lista o un array, simplemente puedes usar el operador de rebanado (es decir, [:]) que creará una copia nueva de la lista.
    2. Al usar PyList_SET_ITEM o PyList_GET_ITEM, debes llamar a Py_INCREF y Py_DECREF, respectivamente, para aumentar y disminuir el recuento de referencias del objeto. Esto es importante porque Python utiliza el recuento de referencias para realizar un seguimiento de la propiedad del objeto y para desasignar objetos no utilizados.

    3. Al acceder a un elemento en una lista anidada, debes utilizar PyList_GET_ITEM o PyList_SET_ITEM para obtener o establecer un elemento. Sin embargo, no debes convertir el resultado a un tipo <object> porque no es un tipo válido de Python. En su lugar, puedes utilizar PyLong_AsLong para convertir el valor a un entero de Python.

    Con estas sugerencias, aquí hay una versión mejorada del código:

    cimport cython
    
    @cython.locals(matrix=object, toClone=object)
    def cloningNodes(matrix, toClone):
        cdef Py_ssize_t matrixSize = len(matrix)
        cdef Py_ssize_t cloneSize = len(toClone)
        cdef Py_ssize_t newSize = matrixSize + cloneSize
        output = [matrix[i][:] for i in range(matrixSize)]
    
        for j in range(cloneSize):
            index = PyLong_AsLong(PyList_GET_ITEM(toClone, j))
    
            if index < 0 or index >= matrixSize:
                # índice fuera de rango
                continue
    
            row = output[index]
            clonedRow = row[:]
            output.append(clonedRow)
    
        return output
    

    En esta versión, el código utiliza una comprensión de lista para crear una nueva copia de cada fila en la matrix. También verifica si el índice en toClone está dentro del rango antes de clonar la fila. Para acceder a un elemento en una lista anidada, utiliza PyList_GET_ITEM y PyLong_AsLong para convertir el índice a un entero de Python.

    ¡Espero que esto ayude!

Comments are closed.