<\/HEAD>
Esta é a segunda parte de uma série em múltiplas partes sobre ArcPy cursors; particularmente, trabalhando com ArcPy cursors como objetos iteráveis em Python. A primeira parte da série<\/A> analisa alguns dos componentes importantes da iteração em Python. A segunda parte da série<\/STRONG> analisa a iteração e o looping sobre ArcPy Data Access cursors. A terceira parte da série <\/A>analisa o uso de várias funções built-in do Python e itertool com ArcPy Data Access cursors. A quarta parte da série abordará o uso de geradores ou expressões geradoras para separar a lógica de seleção ou filtragem para reutilização de código. As partes quinta ou seguintes são desconhecidas neste momento.<\/EM><\/P><\/P>
A primeira parte desta série provavelmente é um pouco acadêmica para alguns scripters de ArcPy, mas acredito que um pouco de teoria ajuda muito a entender a prática de algo, neste caso trabalhar com ArcPy Data Access cursors de forma idiomática. Além disso, os termos e conceitos apresentados no primeiro post aparecerão repetidamente ao longo da série.<\/P>
<\/P>
Antes de prosseguir, farei uma recomendação para uma apresentação de alguns anos atrás:
Loop Like A Native<\/A>. Ned Batchelder <\/A> oferece uma boa visão geral sobre looping em Python, especialmente para aqueles com experiência em looping em outras linguagens de programação. Demorei várias vezes assistindo para que toda a apresentação fizesse sentido, mas realmente mudou a forma como vejo iterar e fazer loop em Python.<\/P><\/P>
Reciclando os exemplos da lista Python e cursor ArcPy do post anterior, vamos chamar iter()<\/SPAN> para retornar um iterador para avançar manualmente por cada iterável.<\/P><SPAN class="operator token">>><\/SPAN><SPAN class="operator token">><\/SPAN> <SPAN class="comment token">#criar lista, anexar 2 iteradores e recuperar valores chamando<\/SPAN>
<SPAN class="operator token">>><\/SPAN><SPAN class="operator token">><\/SPAN> <SPAN class="comment token"># next() e object.next()<\/SPAN>
<SPAN class="operator token">>><\/SPAN><SPAN class="operator token">><\/SPAN> l <SPAN class="operator token">=<\/SPAN> <SPAN class="punctuation token">[<\/SPAN><SPAN class="number token">10<\/SPAN><SPAN class="punctuation token">,<\/SPAN> <SPAN class="number token">20<\/SPAN><SPAN class="punctuation token">,<\/SPAN> <SPAN class="number token">30<\/SPAN><SPAN class="punctuation token">,<\/SPAN> <SPAN class="number token">40<\/SPAN><SPAN class="punctuation token">,<\/SPAN> <SPAN class="number token">50<\/SPAN><SPAN class="punctuation token">]<\/SPAN>
<SPAN class="operator token">>><\/SPAN><SPAN class="operator token">><\/SPAN> it_l <SPAN class="operator token">=<\/SPAN> iter<SPAN class="punctuation token">(<\/SPAN>l<SPAN class="punctuation token">)<\/SPAN>
<SPAN class="operator token">>><\/SPAN><SPAN class="operator token">><\/SPAN> it2_l <SPAN class="operator token">=<\/SPAN> iter<SPAN class="punctuation token">(<\/Span>l<Span class=\"punctuation token\">)<\span>
<span class=\"operator token\">>><\span><span class=\"operator token\">><\span> print next(it_l), next(it2_l)
10 10
>>> print it_l.next(), it2_l.next()
20 20
>>>
>>> #criar search cursor, anexar 2 iteradores e recuperar valores chamando
>>> # next e 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]>)
>>>
<span class=\"line-numbers-rows\"><span><<EMOJI_0>><\span><span><<EMOJI_1>><\span><span><<EMOJI_2>><\span><span><<EMOJI_3>><\span><span><<EMOJI_4>><\span><span><<EMOJI_5>><\span><span><<EMOJI_6>><\span><span><<EMOJI_7>><\span><span><<EMOJI_8>><\span><span><<EMOJI_9>><\span><span><<EMOJI_10>><\span><span><<EMOJI_11>><\span><span><<EMOJI_12>><\span><span><<EMOJI_13>><\span><span><<EMOJI_14>><\span><span><<EMOJI_15>><\span><span><<EMOJI_16>><\span><span><<EMOJI_17>><\span><span><<EMOJI_18>><\span><span><<EMOJI_19>><\span><span><<EMOJI_20>><\span><span><<EMOJI_21>><\span></span>
Há bastante coisa para comentar sobre o código acima:
- Um único iterável pode ter múltiplos iteradores acessando-o simultaneamente. Como o iterável se comporta com múltiplos iteradores é específico da implementação.
iterator <\/A> afirma no Glossário Python, uma lista "produz um novo iterador fresco cada vez que você o passa para uma função iter() ou o usa em um loop for." Isso explica por que as linhas 06-07 e 08-09 estão imprimindo os mesmos valores para ambos os iteradores.<\/LI>Em contraste com a lista Python, o cursor de busca ArcPy Data Access não produz um novo iterador, ou seja, cada chamada subsequente a uma função iter() retorna o mesmo objeto iterador que já está em uso. Nesses tipos de situações, cada chamada a next() avança o iterador um elemento independentemente de qual iterador faça a chamada. Isso explica por que as linhas 16-17 mostram o primeiro e segundo OID em vez de mostrar o primeiro OID duas vezes.<\/LI><\/UL><\/LI>Um iterador pode ser avançado usando a função embutida next() ou o método next do objeto. A partir do Python 3.0, com a adoção do PEP 3114, o método preferido para iterar manualmente é a função embutida next().<\/LI>Como os cursores ArcPy Data Access são seus próprios iteradores, não é necessário chamar iter() para obter um objeto iterador antes de chamar next(). A linha 20 mostra que o próprio objeto cursor pode ser passado para next() para recuperar o próximo item e avançar o cursor.<\/LI><\/UL><\/P>Felizmente para nós, a instrução Python for faz muito trabalho para simplificar os passos para que não precisemos recuperar manualmente um iterador e chamar next() até que o final do iterável seja alcançado.<\/P><\/P>Revisitando a documentação do SearchCursor :<\/P>Resumo<\/P>SearchCursor estabelece acesso somente leitura aos registros retornados de uma classe de feição ou tabela.<\/P><\/P>Retorna um iterador de tuplas. A ordem dos valores na tupla corresponde à ordem dos campos especificados pelo argumento field_names .<\/P>Discussão<\/P>Propriedades Geometry podem ser acessadas especificando o token SHAPE@ na lista de campos.<\/P><\/P>Cursors de busca podem ser iterados usando um loop For. [Removido na versão 10.3.1: Cursors de busca também suportam declarações With; usar uma declaração With garantirá fechamento e liberação dos bloqueios do banco de dados e resetará a iteração].<\/P><\/TD><\/TR><\/TBODY><\/TABLE><\/BLOCKQUOTE><\/P>Como se pode ver, a documentação afirma claramente que o arcpy.da.SearchCursor retorna um iterador, especificamente um iterador de tuplas. Faz sentido retornar tuplas em vez de listas, já que estamos usando um cursor de busca que não pode atualizar dados e tuplas são imutáveis por design. A segunda afirmação na seção Discussão é redundante já que for em Python itera sobre qualquer iterável, SearchCursor ou não, mas essa afirmação não pareceria redundante se a Esri não tivesse removido o restante do parágrafo que costumava seguir.<\/P><\/P>Esta é uma breve digressão sobre uma falha da Esri #fail, um exemplo de como não lidar com feedback do cliente.<\/EM><\/P><\/P>Como mostrado acima, antes do ArcGIS 10.3.1, a Esri incluía algumas declarações sobre declarações Python with . O fato de os cursores ArcPy Data Access suportarem declarações with vale a pena ser destacado, até documentado poderia-se dizer. O problema com as duas declarações era realmente apenas com a última declaração, eu garanto! Garantia é uma palavra forte, definitiva, e o problema é que nem todos os bloqueios do banco de dados são fechados e liberados.<\/EM><\/P><\/P>Um bug foi submetido para atualização da documentação, BUG-000083762: Em cada documentação de cursor, especificar o tipo de bloqueio sendo fechado e liberado, pois um bloqueio compartilhado ainda está presente no geodatabase após a execução da declaração 'with'. O problema foi identificado como "corrigido" no ArcGIS 10.3.1. Se você quiser encontrar essa clarificação sobre bloqueios, eu já mostrei para você. Sim, não há nenhuma, eles simplesmente removeram a declaração sobre bloqueios. Para piorar, também removeram uma declaração muito importante sobre os cursores Data Access suportarem a declaração Python with.<\/EM><\/P><\/P>Embora a documentação fale sobre iteradores e iteração, sinto que uma oportunidade real foi perdida com os exemplos de código para demonstrar um recurso útil do Python. Muitos usuários ArcGIS que são novos em Python aprendem a linguagem imitando exemplos de código. Em termos de mostrar exemplos pythonicos, os cursores ArcPy Data Access são uma mistura.<\/P>Exemplo de Código<\/P>
Use SearchCursor para percorrer uma classe de feição e imprimir valores específicos dos campos e as coordenadas x,y do ponto.<\/P>
<\/P>
| < P >< SPAN style = "font-family:courier new,courier ; " >< SPAN style = "color:#0000ff ; " > import </ SPAN > arcpy </ SPAN >< / P >< P >< / P >< P >< SPAN style = "font-family:courier new,courier ; " > fc = < SPAN style = "color:#a31515 ; " > 'c:/data/base.gdb/well' </ SPAN > </ SPAN >< BR />< SPAN style = "font-family:courier new,courier ; " > fields = [< SPAN style = "color:#a31515 ; " > 'WELL_ID' </ SPAN > , < SPAN style = "color:#a31515 ; " > 'WELL_TYPE' </ SPAN > , < SPAN style = "color:#a31515 ; " > 'SHAPE@XY' </ SPAN > ] </ SPAN >< / P >< P >< / P >< P >< SPAN style = "color:#008000 ; font-family:courier new,courier ; " > # Para cada linha imprima os campos WELL_ID e WELL_TYPE e as coordenadas x,y da feição </ SPAN >< BR />< SPAN style = "color:#008000 ; font-family:courier new,courier ; " > # da feição </ SPAN >< BR />< SPAN style = "font-family:courier new,courier ; " >< SPAN style = "color:#0000ff ; " > with </ SPAN > arcpy.da.SearchCursor(fc, fields) < SPAN style = "color:#0000ff ; " > as </ SPAN > cursor:< / SPAN >< BR />< SPAN style = "font-family:courier new,courier ; " > < SPAN style = "color:#0000ff ; " > for </ SPAN > row < SPAN style = "color:#0000ff ; " > in </ SPAN > cursor:< /SP an >< BR />< SPAN style = "font-family:courier new,courier ; " > < SPAN style = "color:#0000ff ; " > print </ SPAN >(<'{0}, {1}, {2}'>.format(row[0], row[1], row[2]))< / P >< / TD >< / TR >< / TBODY >< / TABLE >< / TD >< / TR >< / TBODY >< / TABLE >< / BLOCKQUOTE >< P > Como apontado na minha digressão anterior/soapbox , a documentação ArcPy Data Access falha em mencionar que os cursores suportam a declaração Python < A href= "https://docs.python.org/2/reference/compound_stmts.html#the-with-statement" rel= "nofollow noopener noreferrer" target= "_blank" > with< /SP an ></ A > .& nbsp ; Dito isso , o suporte é implícito pelo uso das declarações Python with< /SP an ></ A > nos exemplos . & nbsp ; Vale a pena dedicar tempo para estudar as declarações Python with< /SP an ></ A > , e eu incentivo seu uso com cursores ArcPy Data Access sempre que possível .< / P >< P >< / P >< P > Embora os exemplos da documentação demonstrem o uso das declarações Python with< /SP an ></ A > , mesmo que a própria documentação não afirme que são suportadas , os exemplos falham em demonstrar o uso do desempacotamento iterable ou sequência . & nbsp ; Iterable ou sequência desempacotar é um recurso excelente do Python, e pode ser usado para tornar o código muito mais compacto e legível ao mesmo tempo. O desempacotamento de sequência é brevemente mencionado na documentação do Python para Tuples and Sequences, e PEP 3132 -- Extended Iterable Unpacking discute as mudanças introduzidas no Python 3.0. Vamos dar uma olhada em como o desempacotamento iterável pode ser usado com o exemplo 1 do SearchCursor acima. import |