Un cursor es un objeto de acceso a datos que se puede utilizar para recorrer el conjunto de filas de una tabla o insertar nuevas filas en una tabla. Los cursores tienen tres formas: búsqueda, inserción o actualización. Los cursores se utilizan normalmente para leer geometrías existentes y escribir geometrías nuevas.
Cada tipo de cursor se crea con una función de ArcPy (SearchCursor, InsertCursor o UpdateCursor) en una tabla, una vista de tabla, una clase de entidad o una capa de entidades. Un cursor de búsqueda se puede utilizar para recuperar filas. Un cursor de actualización se puede utilizar para actualizar y eliminar filas en función de la posición, mientras que un cursor de inserción se utiliza para insertar filas en una tabla o una clase de entidad.
Cursor | Explicación |
---|---|
arcpy.da.InsertCursor(in_table, field_names) | Inserta filas |
arcpy.da.SearchCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause}) | Acceso de solo lectura |
arcpy.da.UpdateCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause}) | Actualiza o elimina filas |
Cursor | Explicación |
---|---|
arcpy.InsertCursor(dataset, {spatial_reference}) | Inserta filas |
arcpy.SearchCursor(dataset, {where_clause}, {spatial_reference}, {fields}, {sort_fields}) | Acceso de solo lectura |
arcpy.UpdateCursor(dataset, {where_clause}, {spatial_reference}, {fields}, {sort_fields}) | Actualiza o elimina filas |
Se puede navegar a los cursores en la dirección de avance; no permiten retroceder y recuperar filas que ya hayan sido recuperadas. Si una secuencia de comandos necesita pasar varias veces por los datos, se puede invocar el método de cursor reset.
Los cursores de búsqueda o de actualización se pueden recorrer en un bucle for. También se puede obtener acceso a la fila siguiente utilizando de manera explícita el método next integrado de Python para devolver la fila siguiente. Cuando se utiliza el método next en un cursor para recuperar todas las filas de una tabla que contiene N filas, la secuencia de comandos debe realizar N llamadas a next. Una llamada a next después de haber recuperado la última fila del conjunto de resultados devuelve una excepción StopIteration.
import arcpy
cursor = arcpy.da.SearchCursor(fc, ['fieldA', 'fieldB'])
for row in cursor:
print(row)
Los cursores de búsqueda y actualización también son compatibles con las instrucciones with.
import arcpy
with arcpy.da.SearchCursor(fc, ['fieldA', 'fieldB']) as cursor:
for row in cursor:
print(row)
Cada fila recuperada en una tabla se devolverá como una lista de valores de campo. Los valores se devolverán en el mismo orden en que se proporcionaron al argumento field_names del cursor. La propiedad fields de un cursor también se puede utilizar para confirmar el orden de los valores de campo.
El objeto de cursor
SearchCursor, UpdateCursor e InsertCursor crean un objeto de cursor que se puede utilizar para recorrer en iteración los registros. Los métodos del objeto de cursor creados por las diversas funciones de cursor varían, dependiendo del tipo de cursor creado.
El siguiente gráfico muestra los métodos admitidos por cada tipo de cursor:
Tipo de cursor | Método | Efecto sobre la posición |
---|---|---|
arcpy.da.SearchCursor | reset() | Restablece la posición inicial del cursor. |
arcpy.da.InsertCursor | insertRow() |
Inserta una fila en la tabla |
arcpy.da.UpdateCursor |
updateRow() | Actualiza la fila actual |
deleteRow() | Quita la fila de la tabla | |
reset() | Restablece la posición inicial del cursor. |
insertRow
Un cursor de inserción se utiliza para crear nuevas filas e insertarlas. Una vez que se ha creado el cursor, el método insertRow se utiliza para insertar una lista (o tupla) de valores que formarán la nueva fila. Cualquier campo en la tabla que no se incluya en el cursor se asignará al valor predeterminado del campo.
import arcpy
# Create insert cursor for table
#
cursor = arcpy.da.InsertCursor("c:/base/data.gdb/roads_lut",
["roadID", "distance"])
# Create 25 new rows. Set the initial row ID and distance values
#
for i in range(0,25):
cursor.insertRow([i, 100])
updateRow
El método updateRow se utiliza para actualizar la fila en la posición actual de un cursor de actualización. Después de devolver una fila del objeto de cursor, puede modificar la fila como sea necesario y llamar a updateRow para transferir la fila modificada.
import arcpy
# Create update cursor for feature class
#
with arcpy.da.UpdateCursor("c:/base/data.gdb/roads",
["roadtype", "distance"]) as cursor:
for row in cursor:
# Update the values in the distance field by multiplying
# the roadtype by 100. Road type is either 1, 2, 3 or 4.
#
row[1] = row[0] * 100
cursor.updateRow(row)
deleteRow
El método deleteRow se utiliza para eliminar la fila de la posición actual de un cursor de actualización. Después de obtener la fila, llame a deleteRow en el cursor para eliminarla.
import arcpy
# Create update cursor for feature class
#
with arcpy.da.UpdateCursor("c:/base/data.gdb/roads",
["roadtype"]) as cursor:
# Delete all rows that have a roads type of 4
#
for row in cursor:
if row[0] == 4:
cursor.deleteRow()
Acceso y configuración de los valores de campo
Para cada cursor, los campos utilizados se obtienen de una lista (o tupla) de nombres de campo. Cuando el cursor devuelve una fila, la devuelve como una lista de valores de campo que corresponden a una posición del índice.
En el ejemplo siguiente, se obtiene acceso al nombre de estado y al recuento de población por posición.
import arcpy
fc = "c:/base/data.gdb/USA/States"
# Use SearchCursor to access state name and the population count
#
with arcpy.da.SearchCursor(fc, ['STATE_NAME', 'POP2000']) as cursor:
for row in cursor:
# Access and print the row values by index position.
# state name: row[0]
# population: row[1]
#
print('{} has a population of {}'.format(row[0], row[1]))
Los tokens también pueden utilizarse como accesos directos en lugar de nombres de campo. Todas las tablas incluyen un campo ObjectID que puede tener muchos nombres diferentes dependiendo del tipo de datos. Las clases de entidad simples requieren un campo de geometría, por lo general (pero no siempre) denominado Shape. El token OID@ se puede utilizar para obtener acceso al campo ObjectID y el token SHAPE@ (que devuelve un objeto de geometría) se puede utilizar para tener acceso al campo de geometría de una clase de entidad sin saber previamente cuáles son los nombres de campo.
Buscar cursor en una clase de entidad multipunto
import arcpy
infc = arcpy.GetParameterAsText(0)
# Enter for loop for each feature
#
for row in arcpy.da.SearchCursor(infc, ["OID@", "SHAPE@"]):
# Print the current multipoint's ID
#
print("Feature {}:".format(row[0]))
# For each point in the multipoint feature,
# print the x,y coordinates
#
for pnt in row[1]:
print("{}, {}".format(pnt.X, pnt.Y))
Los tokens de geometría adicionales se pueden utilizar para obtener acceso a información de geometría específica. Acceder a la geometría completa es mucho más costoso en términos de tiempo. Si solo necesita propiedades específicas de la geometría, utilice tokens para proporcionar accesos directos a las propiedades de geometría. Por ejemplo, SHAPE@XY devolverá una tupla de las coordenadas x,y que representan el centroide de la entidad.
Cursores y bloqueo
Los cursores de inserción y actualización respetan los bloqueos de tabla establecidos por aplicaciones ArcGIS. Los bloqueos evitan que varios procesos cambien la misma tabla al mismo tiempo. Hay dos tipos de bloqueos: compartidos y exclusivos.
- Un bloqueo compartido se aplica cada vez que se tiene acceso a una tabla o a un dataset. Pueden existir varios bloqueos compartidos para una tabla, pero no se permite ningún bloqueo exclusivo si existe un bloqueo compartido. La visualización de una clase de entidad en ArcMap y la vista previa de una tabla en ArcCatalog son ejemplos de cuándo se aplicaría un bloqueo compartido.
- Los bloqueos exclusivos se aplican cuando se hace algún cambio en una tabla o clase de entidad. Editar y guardar una clase de entidad en ArcMap; cambiar el esquema de una tabla en ArcCatalog; o utilizar un cursor de inserción en una clase de entidad en un IDE de Python, tal como PythonWin, son ejemplos de cuándo aplica ArcGIS un bloqueo exclusivo.
No se puede crear cursores de actualización e inserción para una tabla o clase de entidad si existe un bloqueo exclusivo para ese dataset. Las funciones UpdateCursor o InsertCursor producen un error debido a un bloqueo exclusivo sobre el dataset. Si estas funciones crean un cursor correctamente, aplican un bloqueo exclusivo sobre el dataset para que dos secuencias de comandos no puedan crear un cursor de actualización o inserción en el mismo dataset.
En Python, el bloqueo persiste hasta que se libera el cursor. De lo contrario, se podría impedir a todas las demás aplicaciones o secuencias de comandos el acceso a un dataset. Un cursor se puede liberar mediante una de las siguientes acciones:
- Incluirlo dentro de una instrucción with, que garantizará la liberación de los bloqueos con independencia de si el cursor se completó correctamente o no.
- Llamar a reset() en el cursor
- La finalización del cursor
- Eliminar de forma explícita el cursor por medio de la instrucción del de Python
Una sesión de edición en ArcMap aplica un bloqueo compartido a los datos durante la sesión de edición. Cuando se guardan las ediciones se aplica un bloqueo exclusivo. Un dataset no es editable si ya existe un bloqueo exclusivo.
Cursores y campos BLOB
Los objetos binarios grandes (BLOB) son datos almacenados como una secuencia larga de números binarios. En ArcGIS, las anotaciones y dimensiones se almacenan como BLOB y los elementos, como imágenes, multimedia o bits de código, se pueden almacenar en este tipo de campo. Puede utilizar un cursor para cargar o visualizar el contenido de un campo BLOB.
En Python, los campos BLOB pueden aceptar cadenas de caracteres, bytearray y memoryviews. Al leer los campos BLOB, se devuelve un objeto memoryview.
import arcpy
data = open("c:/images/image1.png", "rb").read()
ic = arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['imageblob'])
ic.insertRow([data])
import arcpy
sc = arcpy.da.SearchCursor("c:/data/fgdb.gdb/fc", ["imageblob"])
memview = sc.next()[0]
open("c:/images/image1_copy.png", "wb").write(memview.tobytes())