12 votos

¿Eliminar el cursor utilizado en SearchCursor dentro de una comprensión de diccionario?

Si es mejor abrir cursores usando una declaración with para asegurarse de que se borre, como se muestra a continuación:

with arcpy.da.UpdateCursor(fc,fields) as cursor:

Luego, si un cursor se usa como iterable en una comprensión como se muestra a continuación:

d = {k:v for (k,v) in arcpy.da.SearchCursor(fc,fields)}

¿Es necesario borrar el cursor después de usarlo en la comprensión?

1 votos

Gran pregunta. ¿Estás tratando de manejar bloqueos de esquema? Hay algunos artículos antiguos (en su mayoría desactualizados) sobre un tema similar, aunque no puedo encontrar una fuente definitiva sobre los nuevos cursores da: sgillies.net/2011/02/01/get-with-it.html y help.arcgis.com/en/arcgisdesktop/10.0/help/index.html#//…. En particular, mira los comentarios de @JasonScheirer al final del primer enlace.

13voto

user8548 Puntos 188

Si es absolutamente necesario es la pregunta incorrecta para hacer. La pregunta es si es una buena idea.

Como regla en programación, deberías evitar hacer cosas extrañas y usar la mejor herramienta para el trabajo. Si algo tiene una forma explícita de liberar recursos, simplemente haz la liberación explícita y listo:

with arcpy.da.UpdateCursor(fc,fields) as cursor:
    d = {k: v for (k,v) in cursor}

Lo que quizás no sepas es que la cláusula with en realidad invoca lógica adicional. Una cláusula with requiere un administrador de contexto, que debe tener un método __enter__ (invocado cuando se ingresa al bloque) y un método __exit__ (invocado cuando se sale del bloque). En particular, el método __exit__ se invoca independientemente de si ocurrió una excepción, asegurando que el programa siempre libere el recurso incluso en caso de error. Esto le da a tu código una documentación explícita de cuándo se adquiere un recurso y cuándo se libera, y asegura que un recurso se pueda liberar tan pronto como sea posible.

Por el contrario, en realidad no puedes depender de que se cierre de inmediato automáticamente. Esto se debe a que la forma en que se cierra es invocando el destructor del objeto, lo que puede o no ocurrir de inmediato. Python no ofrece garantías sobre cuándo se invoca un destructor, sólo que eventualmente lo hará cuando el objeto sea recolectado por la basura. (Ver aquí.) Actualmente, Python está implementado de modo que sucede tan pronto como ya no hay una referencia al objeto. Pero es fácil propagar referencias accidentalmente a un objeto, y el tiempo de ejecución de Python podría cambiar.

También considera el mantenimiento a largo plazo. Ahora no hay una referencia a largo plazo, pero ¿qué sucede en 6 meses cuando necesites modificar el código para que haya una referencia? ¿Qué pasa si alguien más lo hace? La persona que realiza el cambio puede que no piense en cambiar a un bloque with ya que no hay uno presente. Hacer de la limpieza de tus recursos un hábito te evitará muchos problemas.

¿Realmente quieres atar tu código a los detalles de implementación de la recolección de basura? ¿Quieres tener que pensar constantemente si podrías estar propagando accidentalmente una referencia a través de una excepción? No, no lo quieres. Imagina si eso sucediera cuando el script fuera invocado en ArcMap. El usuario se vería obligado a cerrar todo el proceso solo para liberar el archivo. Así que no te pongas en esa posición. Libera el recurso explícitamente. No vale la pena arriesgarte a problemas que puede causar el guardar una línea de código. Los administradores de contexto son el mecanismo estándar para adquirir y liberar recursos en Python, y lo hacen muy bien.

En resumen, no liberarlo explícitamente es una mala idea.

Esto, por supuesto, asume que el código tiene alguna posibilidad de afectar a alguien más, como ponerlo en un script que alguien más tendrá que ejecutar o mantener, o podría retrasar la entrega de tu trabajo si tienes que cerrar ArcMap por completo porque no puedes guardar tus cambios. Si eres el único que se verá afectado por un problema, entonces adelante, desatiende las buenas prácticas todo lo que quieras.

3voto

gar Puntos 36

No, no es necesario borrar un cursor después de usarlo en una comprensión. Un cursor es una instancia de una clase, que es un objeto (todo en python es un objeto). Cada sesión de python tiene un namespace que contiene referencias a todos los objetos en la sesión, piénselo como un diccionario donde las claves son referencias a cada objeto y los valores son los propios objetos. Cuando el 'conteo de referencias' - el número de claves que se refieren a ese objeto - cae a cero, el objeto es eliminado y la memoria es realojada. Cuando se usa un cursor en una comprensión, no hay referencia a ese objeto en el namespace. Después de que la comprensión haya terminado, el objeto será eliminado.

No hay una entrada en el namespace y por lo tanto no hay necesidad de borrar nada. ESRI también ilustra esta sintaxis en el ejemplo 2, aquí.

Para mayor claridad, si ejecutas:

>>> import arcpy
>>> f = r'C:\Workspace\study_area.shp'
>>> a = arcpy.da.SearchCursor(f, ['*'])

Verás un archivo .lock aparecer en el directorio (verifica en tu explorador de archivos). La referencia al cursor es a, lo que hará que el cursor (y por lo tanto el bloqueo) persista hasta que se elimine a. Entonces cuando ejecutes:

>>> del(a)

La entrada en el namespace será eliminada y el bloqueo se liberará (el archivo .lock desaparecerá). Si ejecutas:

>>> t = [i for i in arcpy.da.SearchCursor(f, ['*'])]

No verás un archivo de bloqueo, o desaparecerá cuando el comando se complete. Sin una entrada en el namespace, el cursor no es persistente. t se refiere a la lista que acabas de crear, no al cursor que se utilizó para crearla.

En resumen, solo necesitas preocuparte por borrar cursors cuando tengan una referencia en el namespace (es decir, cuando los hayas asignado a una variable, como a en el ejemplo anterior).

2 votos

Esto es una práctica de programación extremadamente deficiente. Si algo tiene una forma explícita de liberar recursos, úsala.

0 votos

@jpmc26, ¿Cuál parte es una "práctica de programación extremadamente pobre"? ¿Las comprensiones en general? ¿O solo si el iterable se instancia dentro de la comprensión? Pensé que un argumento fuerte a favor de esto último es que libera inmediatamente el recurso.

0 votos

@Tom No liberar recursos explícitamente. Las comprensiones son herramientas fantásticas, e instanciar iterables normales dentro de ellas es completamente normal. Lo malo aquí es que los objetos de cursor adquieren bloqueos de archivos y no hay una liberación explícita de ellos. Vea mi respuesta para más detalles.

2voto

jbalk Puntos 581

Las cursores de actualización e inserción no se pueden crear para una tabla o clase de entidad si existe un bloqueo exclusivo para ese conjunto de datos. Las funciones UpdateCursor o InsertCursor fallan debido a un bloqueo exclusivo en el conjunto de datos. Si estas funciones crean con éxito un cursor, aplican un bloqueo exclusivo en el conjunto de datos para que dos scripts no puedan crear un cursor de actualización o inserción en el mismo conjunto de datos.

En Python, el bloqueo persiste hasta que se libera el cursor. De lo contrario, todas las demás aplicaciones o scripts podrían ser innecesariamente prevenidos de acceder a un conjunto de datos. Un cursor se puede liberar mediante uno de los siguientes métodos:

Incluyendo el cursor dentro de una declaración with, lo que garantizará la liberación de los bloqueos sin importar si el cursor se completa exitosamente o no;

Llamando a reset() en el cursor;

La finalización del cursor;

Eliminando explícitamente el cursor usando la declaración del de Python - ESRI

El bloqueo con cursores arcpy.da es prácticamente igual que el bloqueo con los cursores originales de arcpy.

Después de probar tu código, y como señaló gberard, no hay referencia al cursor después de que finaliza la comprensión.
Además, no hay bloqueos en la clase de entidad después de que finaliza la comprensión.

1 votos

Borrando qué? No hay referencia al objeto cursor después de que termine la comprensión, por lo que teóricamente debería cerrarse. Si la implementación de ESRI se comporta como esperarías es otra cuestión, y no creo que los documentos realmente respondan a eso.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X