<\/HEAD>
Ceci est le deuxième volet d'une série en plusieurs parties sur les curseurs ArcPy ; en particulier, travailler avec les curseurs ArcPy en tant qu'objets itérables en Python. La première partie de la série<\/A> examine certains des composants importants de l'itération en Python. La deuxième partie de la série<\/STRONG> porte sur l'itération et la boucle sur les curseurs ArcPy Data Access. La troisième partie de la série <\/A>examine l'utilisation de plusieurs fonctions intégrées Python et itertools avec les curseurs ArcPy Data Access. La quatrième partie de la série portera sur l'utilisation des générateurs ou des expressions génératrices pour séparer la logique de sélection ou de filtrage afin de réutiliser le code. Les cinquième et parties suivantes sont inconnues à ce jour.<\/EM><\/P><\/P>
La première partie de cette série est probablement un peu académique pour certains scriptistes ArcPy, mais je crois qu'un peu de théorie aide grandement à comprendre la pratique de quelque chose, dans ce cas travailler avec les curseurs ArcPy Data Access d'une manière idiomatique. De plus, les termes et concepts exposés dans le premier article reviendront encore et encore tout au long de la série.<\/P>
<\/P>
Avant de continuer, je vais faire la promotion d'une présentation d'il y a quelques années :
Loop Like A Native<\/A>. Ned Batchelder <\/A>donne un bon aperçu des boucles en Python, surtout pour ceux qui ont une expérience des boucles dans d'autres langages de programmation. Il m'a fallu plusieurs visionnages pour que toute la présentation s'imprègne, mais cela a vraiment changé ma façon de voir l'itération et les boucles en Python.<\/P><\/P>
En recyclant les exemples de liste Python et de curseur ArcPy du post précédent, appelons iter()<\/SPAN> pour retourner un itérateur permettant d'avancer manuellement à travers chaque itérable.<\/P><SPAN class="operator token">>><\/SPAN><SPAN class="operator token">><\/SPAN> <SPAN class="comment token">#créer une liste, attacher 2 itérateurs, et récupérer les valeurs par<\/SPAN>
<SPAN class="operator token">>><\/SPAN><SPAN class="operator token">><\/SPAN> <SPAN class="comment token"># appel à next() et 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
>> >
>> > #créer un curseur de recherche, attacher 2 itérateurs, et récupérer les valeurs par
>> > # appel à next et 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>
Il y a pas mal de choses à commenter avec le code ci-dessus :
- Un seul itérable peut avoir plusieurs itérateurs y accédant simultanément. La façon dont l'itérable se comporte avec plusieurs itérateurs dépend de l'implémentation.
définition d'itérateur<\/> dans le rel="nofollow noopener noreferrer" target="_blank">Glossaire Python, une liste "produit un nouvel itérateur frais à chaque fois que vous le passez à une fonction iter() ou que vous l'utilisez dans une boucle for." Cela explique pourquoi les lignes 06-07 et 08-09 affichent les mêmes valeurs pour les deux itérateurs.<\/LI>Contrairement à la liste Python, le curseur de recherche ArcPy Data Access ne produit pas un nouvel itérateur, c'est-à-dire que chaque appel ultérieur à une fonction iter() renvoie le même objet itérateur qui est déjà en cours d'utilisation. Dans ce type de situation, chaque appel à next() avance l'itérateur d'un élément quel que soit l'itérateur qui fait l'appel. Cela explique pourquoi les lignes 16-17 montrent le premier et le deuxième OID au lieu de montrer le premier OID deux fois.<\/LI><\/UL><\/LI>Un itérateur peut être avancé en utilisant soit la fonction intégrée next() soit la méthode next de l'objet. À partir de Python 3.0, avec l'adoption de PEP 3114, la méthode préférée pour itérer manuellement est la fonction intégrée next().<\/LI>Puisque les curseurs ArcPy Data Access sont leurs propres itérateurs, il n'est pas nécessaire d'appeler iter() pour obtenir un objet itérateur avant d'appeler next(). La ligne 20 montre que l'objet curseur lui-même peut être passé à next() pour récupérer l'élément suivant et avancer le curseur.<\/LI><\/UL><\/P>Heureusement pour nous, l'instruction Python for fait beaucoup de travail pour simplifier les étapes afin que nous n'ayons pas à récupérer manuellement un itérateur et appeler next() jusqu'à ce que la fin de l'itérable soit atteinte.<\/P><\/P>Revenons à la documentation du SearchCursor :<\/P>Résumé<\/P>SearchCursor établit un accès en lecture seule aux enregistrements retournés d'une classe d'entités ou d'une table.<\/P><\/P>Renvoie un itérateur de tuples. L'ordre des valeurs dans le tuple correspond à l'ordre des champs spécifiés par l'argument field_names .<\/P>Discussion<\/P>Les propriétés Geometry peuvent être accédées en spécifiant le jeton SHAPE@ dans la liste des champs.<\/P><\/P>Les curseurs de recherche peuvent être itérés en utilisant une boucle For. [Supprimé à la version 10.3.1: Les curseurs de recherche supportent également les instructions With ; utiliser une instruction With garantira la fermeture et la libération des verrous de base de données et réinitialisera l'itération].<\/P><\/TD><\/TR><\/TBODY><\/TABLE><\/BLOCKQUOTE><\/P>Comme on peut le voir, la documentation indique clairement que arcpy.da.SearchCursor renvoie un itérateur, un itérateur de tuples pour être précis. Il est logique qu'il renvoie des tuples plutôt que des listes puisque nous utilisons un curseur de recherche qui ne peut pas mettre à jour les données et que les tuples sont immuables par conception. La deuxième affirmation dans la section Discussion est redondante puisque for en Python itère sur tout objet itérable, SearchCursor ou autre, mais cette affirmation ne ressortirait pas comme redondante si Esri n'avait pas supprimé le reste du paragraphe qui suivait.<\/P><\/P>Ceci est une digression pas si rapide sur un échec Esri #fail, un exemple de comment ne pas gérer les retours clients.<\/EM><\/P><\/P>Comme montré ci-dessus, avant ArcGIS 10.3.1, Esri incluait quelques affirmations concernant les instructions Python with . Le fait que les curseurs ArcPy Data Access supportent les instructions with mérite d'être souligné, voire documenté pourrait-on dire. Le problème avec ces deux affirmations était vraiment juste un problème avec la dernière affirmation, je vous le garantis ! Garantir est un mot fort, un mot définitif, et le problème est que tous les verrous de base de données ne sont pas fermés et libérés.<\/EM><\/P><\/P>Bogue soumis pour mise à jour de la documentation, BUG-000083762 : Dans chaque documentation de curseur, spécifier le type de verrou fermé et libéré, car un verrou partagé est toujours présent dans la géodatabase après l'exécution de l'instruction 'with'. Le problème a été identifié comme "corrigé" dans ArcGIS 10.3.1. Si vous voulez trouver cette clarification sur les verrous, je vous l'ai déjà montrée. Oui, il n'y en a pas, ils ont simplement supprimé l'affirmation concernant les verrous. Pour aggraver les choses, ils ont aussi supprimé une déclaration très importante concernant le support des curseurs Data Access pour l'instruction Python with.<\/EM><\/P><\/P>Même si la documentation parle des itérateurs et de l'itération, je pense qu'une vraie opportunité a été manquée avec les exemples de code pour démontrer une fonctionnalité pratique de Python. Beaucoup d'utilisateurs ArcGIS débutants en Python apprennent le langage en imitant des exemples de code. En termes d'exemples pythonic, les curseurs ArcPy Data Access sont mitigés.<\/P>Exemple de code<\/P>Exemple SearchCursor 1
< P > Utilisez SearchCursor pour parcourir une classe d'entités et imprimer des valeurs spécifiques des champs ainsi que les coordonnées x,y du point.< / P >< P >< / P >< TABLE style = "width :95 % ; border :1 px solid lightgrey ; background-color :#fafafa ; " >< TBODY >< TR >< TD >< 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 ; " ># Pour chaque ligne imprimez les champs WELL_ID et WELL_TYPE, ainsi que< / SPAN >< BR />< SPAN style = "color :#008000 ; font-family :courier new ,courier ; " ># les coordonnées x,y de l'entité< / 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:< / SPAN >< BR />< SPAN style = "font-family :courier new ,courier ; " > < SPAN style = "color :#0000ff ; " >print< / SPAN >(<'{0}, {1}, {2}'>.format(row[0], row[1], row[2]))< / SPAN >< / P >< / TD >< / TR >< / TBODY >< / TABLE >< / TD >< / TR >< / TBODY >< / TABLE >< / BLOCKQUOTE >< P > Comme indiqué dans ma digression précédente/prise de parole, la documentation ArcPy Data Access ne mentionne pas que les curseurs supportent l'instruction Python < A href ="
https://docs.python.org/2/reference/compound_stmts.html#the-with-statement" rel= "nofollow noopener noreferrer" target= "_blank" > with </ A > .& nbsp ; Cela dit, le support est implicite par l'utilisation des instructions Python < span style= "font-family:courier new,courier" > with </ span > dans les exemples . & nbsp ; Il vaut la peine de se renseigner sur les instructions Python < span style= "font-family:courier new,courier" > with </ span > , et j'encourage leur utilisation avec les curseurs ArcPy Data Access chaque fois que possible . </ p > < p ></ p > < p > Alors que les exemples dans la documentation démontrent l'utilisation des instructions Python < span style= "font-family:courier new,courier" > with </ span > , même si la documentation elle-même ne dit pas qu'elles sont supportées , ces exemples ne montrent pas non plus l'utilisation du déballage d'itérables ou séquences . & nbsp ; Itérable ou séquence le déballage est une fonctionnalité géniale de Python, et il peut être utilisé pour rendre le code beaucoup plus compact et lisible en même temps. Le déballage de séquence est brièvement mentionné dans la documentation Python pour
Tuples and Sequences, et
PEP 3132 -- Extended Iterable Unpacking discute des changements introduits dans Python 3.0.
Jetons un coup d'œil à la façon dont le déballage itérable peut être utilisé avec l'exemple SearchCursor 1 ci-dessus.
import