<\/HEAD>
Esta es la segunda parte de una serie multipartita sobre ArcPy cursors; en particular, trabajando con ArcPy cursors como objetos iterables en Python. La primera parte de la serie<\/A> analiza algunos de los componentes importantes de la iteración en Python. La segunda parte de la serie<\/STRONG> examina la iteración y el bucle sobre ArcPy Data Access cursors. La tercera parte de la serie <\/A>analiza el uso de varias funciones integradas de Python y itertool con ArcPy Data Access cursors. La cuarta parte de la serie abordará el uso de generadores o expresiones generadoras para separar la lógica de selección o filtrado para la reutilización del código. Las partes quinta o siguientes son desconocidas por el momento.<\/EM><\/P><\/P>
La primera parte de esta serie probablemente sea un poco académica para algunos scripters de ArcPy, pero creo que un poco de teoría ayuda mucho a entender la práctica de algo, en este caso trabajar con ArcPy Data Access cursors de manera idiomática. Además, los términos y conceptos expuestos en la primera publicación aparecerán una y otra vez a lo largo de la serie.<\/P>
<\/P>
Antes de continuar, quiero recomendar una presentación de hace algunos años:
Loop Like A Native<\/A>. Ned Batchelder <\/A>ofrece una buena visión general del bucle en Python, especialmente para aquellos con experiencia en bucles en otros lenguajes de programación. Me tomó varias veces verla para que toda la presentación calara, pero realmente cambió la forma en que veo la iteración y los bucles en Python.<\/P><\/P>
Reciclando los ejemplos de listas y ArcPy cursor del post anterior, llamemos a iter()<\/SPAN> para devolver un iterador para avanzar manualmente a través de cada iterable.<\/P>>><\/SPAN>><\/SPAN> #crear lista, adjuntar 2 iteradores y recuperar valores mediante<\/SPAN>
>><\/SPAN>><\/SPAN> # llamada a next() y object.next()<\/SPAN>
>><\/SPAN>><\/SPAN> l =<\/SPAN> [<\/SPAN>10<\/SPAN>,<\/SPAN> 20<\/SPAN>,<\/SPAN> 30<\/SPAN>,<\/SPAN> 40<\/SPAN>,<\/SPAN> 50<\/SPAN>]<\/SPAN>
>><\/SPAN>><\/SPAN> it_l =<\/SPAN> iter(<\/SPAN>l)<\/SPAN>
>><\/SPAN>><\/SPAN> it2_l =<\/SPAN> iter(<\/Span>l)<\span>
>><\span>><\span> print next(it_l), next(it2_l)
10 10
>> print it_l.next(), it2_l.next()
20 20
>>
>> #crear search cursor, adjuntar 2 iteradores y recuperar valores mediante
>> # llamada a next y object.next()
>> cur = arcpy.da.SearchCursor(fc, ["OID@", "SHAPE@"])
>> it_cur = iter(cur)
>> it2_cur = iter(cur)
>> print next(it_cur), next(it2_cur)
(1, <Polyline object at 0x1100fcf0[0x1100ff20]>) (2, <Polyline object at 0x1100fcf0[0x1100ff20]>)
>> print it_cur.next(), it2_cur.next()
(3, <Polyline object at 0x1100fcf0[0x1100ff20]>) (4, <Polyline object at 0x1100fcf0[0x1100ff20]>)
>> print next(cur)
(5, <Polyline object at 0x1100fcf0[0x1100ff20]>)
>>
<<EMOJI_0></span><<EMOJI_1></span><<EMOJI_2></span><<EMOJI_3></span><<EMOJI_4></span><<EMOJI_5></span><<EMOJI_6></span><<EMOJI_7></span><<EMOJI_8></span><<EMOJI_9></span><<EMOJI_10></span><<EMOJI_11></span><<EMOJI_12></span><<EMOJI_13></span><<EMOJI_14></span><<EMOJI_15></span><<EMOJI_16></span><<EMOJI_17></span><<EMOJI_18></span><<EMOJI_19></span><<EMOJI_20></span><<EMOJI_21>
Hay bastante que comentar sobre el código anterior:
- Un solo iterable puede tener múltiples iteradores accediendo simultáneamente. Cómo se comporta el iterable con múltiples iteradores depende de la implementación.
- Como indica la definición del
iterator <\/> rel="nofollow noopener noreferrer" target="_blank">Glosario de Python, una lista "produce un nuevo iterador fresco cada vez que lo pasas a una función iter() o lo usas en un bucle for." Esto explica por qué las líneas 06-07 y 08-09 imprimen los mismos valores para ambos iteradores.<\/LI>En contraste con la lista de Python, el cursor de búsqueda ArcPy Data Access no produce un nuevo iterador, es decir, cada llamada subsecuente a una función iter() devuelve el mismo objeto iterador que ya está en uso. En este tipo de situaciones, cada llamada a next() avanza el iterador un elemento sin importar qué iterador haga la llamada. Esto explica por qué las líneas 16-17 muestran el primer y segundo OID en lugar de mostrar el primer OID dos veces.<\/LI><\/UL><\/LI>Un iterador puede avanzar usando ya sea la función incorporada next() o el método next del objeto. A partir de Python 3.0, con la adopción de PEP 3114, el método preferido para iterar manualmente es la función incorporada next().<\/LI>Dado que los cursores ArcPy Data Access son su propio iterador, no es necesario llamar a iter() para obtener un objeto iterador antes de llamar a next(). La línea 20 muestra que el propio objeto cursor puede pasarse a next() para recuperar el siguiente elemento y avanzar el cursor.<\/LI><\/UL><\/P>Afortunadamente para nosotros, la sentencia Python for hace mucho trabajo para simplificar los pasos para que no tengamos que recuperar manualmente un iterador y llamar a next() hasta que se alcance el final del iterable.<\/P><\/P>Revisando la documentación del SearchCursor :<\/P>Resumen<\/P>SearchCursor establece acceso de solo lectura a los registros devueltos de una clase de entidad o tabla.<\/P><\/P>Devuelve un iterador de tuplas. El orden de los valores en la tupla coincide con el orden de los campos especificados por el argumento field_names .<\/P>Discusión<\/P>Las propiedades Geometry pueden accederse especificando el token SHAPE@ en la lista de campos.<\/P><\/P>Los cursores de búsqueda pueden ser iterados usando un bucle For. [Eliminado en 10.3.1: Los cursores de búsqueda también soportan sentencias With; usar una sentencia With garantizará cerrar y liberar bloqueos de base de datos y reiniciar la iteración].<\/P><\/TD><\/TR><\/TBODY><\/TABLE><\/BLOCKQUOTE><\/P>Como se puede ver, la documentación claramente indica que arcpy.da.SearchCursor devuelve un iterador, específicamente un iterador de tuplas. Tiene sentido que devuelva tuplas en lugar de listas ya que estamos usando un cursor de búsqueda que no puede actualizar datos y las tuplas son inmutables por diseño. La segunda afirmación en la sección Discusión es redundante ya que for en Python itera sobre cualquier iterable, SearchCursor o no, pero esa afirmación no destacaría como redundante si Esri no hubiera eliminado el resto del párrafo que solía seguir.<\/P><\/P>Este es un aparte no tan rápido sobre un #fail de Esri, un ejemplo de cómo no manejar la retroalimentación del cliente.<\/EM><\/P><\/P>Como se mostró arriba, antes de ArcGIS 10.3.1, Esri incluía un par de afirmaciones respecto a las sentencias Python with . El hecho de que los cursores ArcPy Data Access soporten sentencias with vale la pena destacarlo, incluso documentarlo podría decirse. El problema con las dos afirmaciones era realmente solo con la última afirmación, ¡lo garantizo! Garantizar es una palabra fuerte, definitiva, y el problema es que no todos los bloqueos de base de datos se cierran y liberan.<\/EM><\/P><\/P>Se presentó un error para actualizar la documentación, BUG-000083762: En cada documentación del cursor, especificar el tipo de bloqueo que se cierra y libera, ya que un bloqueo compartido sigue presente en la geodatabase después de ejecutar la sentencia 'with'. El problema fue identificado como "arreglado" en ArcGIS 10.3.1. Si quieres encontrar esa aclaración sobre bloqueos, ya te la mostré. Sí, no hay ninguna, simplemente eliminaron la afirmación sobre bloqueos. Para colmo, también eliminaron una afirmación muy importante sobre que los cursores Data Access soportan la sentencia Python with.<\/EM><\/P><\/P>Aunque la documentación habla sobre iteradores e iterar, siento que se perdió una oportunidad real con los ejemplos de código para demostrar una característica útil de Python. Muchos usuarios de ArcGIS nuevos en Python aprenden el lenguaje emulando ejemplos de código. En términos de mostrar ejemplos pythonicos, los cursores ArcPy Data Access son una mezcla.<\/P>Ejemplo de Código<\/P>Ejemplo SearchCursor 1
Usa SearchCursor para recorrer una clase de entidad e imprimir valores específicos del campo y las coordenadas x,y del punto.<\/P>
<\/P>
importar arcpy fc = 'c:\/data/base.gdb/well'fields = ['WELL_ID', 'WELL_TYPE', 'SHAPE@XY'] # Para cada fila imprime los campos WELL_ID y WELL_TYPE, y las# coordenadas x,y del featurecon arcpy.da.SearchCursor(fc, fields) as cursor: for row in cursor: print('{0}, {1}, {2}'.format(row[0], row[1], row[2])) |
Como señalé en mi anterior tribuna/aparte , la documentación ArcPy Data Access no menciona que los cursores soportan la sentencia Python with . & nbsp ; Eso sí , el soporte está implícito por el uso de sentencias Python < span style = "font-family : courier new , courier ; " > with </ span > en los ejemplos . & nbsp ; Vale la pena leer sobre las sentencias Python < span estilo = "fuente-familia : courrier nouveau , courrier ; " > avec </ span > , y animo su uso con cursores ArcPy Data Access siempre que sea posible . </ p >< p >< / p >< p > Mientras que los ejemplos en la documentación demuestran usar sentencias Python < span estilo = "fuente-familia : courrier nouveau , courrier ; " > avec </ span > , aunque la propia documentación no indica que estén soportadas , los ejemplos sí fallan al demostrar el uso del desempaquetado iterable o secuencia . & nbsp ; Iterable o secuencia desempaquetar es una gran característica de Python, y se puede usar para hacer el código mucho más compacto y legible al mismo tiempo. El desempaquetado de secuencias se menciona brevemente en la documentación de Python para Tuplas y Secuencias, y PEP 3132 -- Extended Iterable Unpacking discute los cambios introducidos en Python 3.0.
Veamos cómo se puede usar el desempaquetado iterable con el ejemplo 1 de SearchCursor de arriba.
import