<\/HEAD>
Ceci est le premier 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<\/STRONG> examine certains des composants importants de l'itération en Python. La deuxième partie de la série <\/A>porte sur l'itération et la boucle sur les curseurs ArcPy Data Access. La troisième partie de la série <\/A>traite de 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 examinera 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>
Cette série et les articles de blog suivants se concentrent sur les
curseurs ArcPy Data Access<\/A> dans le contexte de l'itération, d'où le titre de la série. Maintenant, il pourrait sembler absurde de parler de curseurs itérables puisque un curseur est essentiellement inutile sans itération, mais mon expérience du scripting avec les curseurs ArcPy et des réponses aux questions sur GeoNet m'a motivé à partager quelques façons pythoniennes de penser et de travailler avec les curseurs.<\/P><\/P>
Quand on parle d'itération en Python, il existe de nombreux termes et expressions qui peuvent être pertinents pour une discussion. Cinq termes que je considère particulièrement importants et pertinents pour cette série d'articles sont :<\/P>
Glossaire<\/A><\/SPAN><\/P>generator<\/STRONG><\/P>Une fonction qui retourne un itérateur. Elle ressemble à une fonction normale sauf qu'elle contient des instructions
yield<\/SPAN> <\/A>pour produire une série de valeurs utilisables dans une boucle for ou qui peuvent être récupérées une par une avec la fonction next()<\/A><\/SPAN>. Chaque yield<\/SPAN> <\/A>suspend temporairement le traitement, mémorisant l'état d'exécution (y compris les variables locales et les instructions try en attente). Lorsque le générateur reprend, il continue là où il s'était arrêté (contrairement aux fonctions qui recommencent à chaque appel).<\/P><\/P>generator expression<\/STRONG><\/P>Une expression qui retourne un itérateur. Elle ressemble à une expression normale suivie d'une expression for<\/SPAN> <\/A>définissant une variable de boucle, une plage, et une expression optionnelle if<\/A><\/SPAN>. L'expression combinée génère des valeurs pour une fonction englobante :<\/P><SPAN class="operator token">>><\/SPAN><SPAN class="operator token">><\/SPAN> sum<SPAN class="punctuation token">(<\/SPAN>i<SPAN class="operator token">*< \/span>i <span class=\"keyword token\">for< \/span> i <span class=\"keyword token\">in< \/span> range<SPAN class=\"punctuation token\">(< \/span><span class=\"number token\">10< \/span><span class=\"punctuation token\">)< \/span><span class=\"punctuation token\">)< \/span> <span class=\"comment token\"># somme des carrés 0, 1, 4, ... 81< \/span>
<span class=\"number token\">285< \/span>
<span class=\"line-numbers-rows\"><span><<EMOJI_0>>< \/span><span><<EMOJI_1>>< \/span></span>
< \/P>
iterable< \/STRONG>
Un objet capable de retourner ses membres un par un. Les exemples d'itérables incluent tous les types de séquences (comme
list< \/A>, str< \/A>, et tuple< \/A>) ainsi que certains types non-séquence comme dict< \/A> et file< \/A> et des objets de toutes classes que vous définissez avec une méthode __iter__()< \/A> ou __getitem__()< \/A>. Les itérables peuvent être utilisés dans une boucle for < \/ A > </ SPAN > et dans beaucoup d'autres endroits où une séquence est nécessaire (< SPAN style = \ "font-family : courier new,courier ; \ " > < A href = \ "https : \/ \/ docs.python.org \/ 2 \/ library \/ functions.html # zip \ " rel = \ "nofollow noopener noreferrer \ " target = \ "_ blank \ " > zip() < \/ A > </ SPAN > , < SPAN style = \ "font-family : courier new,courier ; \ " > < A href = \ "https : \/ \/ docs.python.org \/ 2 \/ library \/ functions.html # map \ " rel = \ "nofollow noopener noreferrer \ " target = \ "_ blank \ " > map() < \/ A > </ SPAN > , ...). Lorsqu'un objet itérable est passé comme argument à la fonction intégrée < SPAN style = \ "font-family : courier new,courier ; \ " > < A href = \ "https : \/ \/ docs.python.org \/ 2 \/ library \/ functions.html # iter \ " rel = \ "nofollow noopener noreferrer \ " target = \ "_ blank \ " > iter() < \/ A > </ SPAN > , elle retourne un itérateur pour l'objet. Cet itérateur est bon pour un passage unique sur l'ensemble des valeurs. Lorsqu'on utilise des itérables, il n'est généralement pas nécessaire d'appeler soi-même < SPAN style = \ "font-family : courier new,courier ; \ " > < A href = \ "https : \/ \/ docs.python.org \/ 2 \/ library \/ functions.html # iter \ " rel = \ "nofollow noopener noreferrer \ " target = \ "_ blank \ " > iter() < \/ A > </ SPAN > ou de gérer les objets itérateurs. L'instruction < SPAN style = \ "font-family : courier new,courier ; background-color : #e0e0e0 ; \ " > for < / SPAN > fait cela automatiquement pour vous, créant une variable temporaire anonyme pour contenir l'itérateur pendant toute la durée de la boucle. Voir aussi iterator, sequence, et generator.< / P >< P >< / P >< P >< STRONG > iterator < / STRONG >< / P >< P style = "margin-left: 30px; " > Un objet représentant un flux de données. Des appels répétés à la méthode next() de l’itérateur retournent successivement les éléments du flux. Quand il n’y a plus de données disponibles, une exception StopIteration est levée. À ce moment-là, l’objet itérateur est épuisé et tout appel ultérieur à sa méthode next() lèvera encore StopIteration. Les itérateurs doivent avoir une méthode __iter__() qui retourne l’objet itérateur lui-même, donc chaque itérateur est aussi un itérable et peut être utilisé dans la plupart des endroits où d’autres itérables sont acceptés. Une exception notable concerne le code qui tente plusieurs passages d’itération. Un objet conteneur (comme une liste) produit un nouvel itérateur frais chaque fois que vous le passez à la courier new,courier;">iter() fonction ou l'utiliser dans une boucle for. Tenter cela avec un itérateur renverra simplement le même objet itérateur épuisé utilisé lors du passage d'itération précédent, donnant l'impression d'un conteneur vide.
sequence
Un iterable qui supporte un accès efficace aux éléments en utilisant des indices entiers via la méthode spéciale __getitem__() et définit une méthode len() qui retourne la longueur de la séquence. Certains types de séquences intégrés sont list, str, tuple, et unicode. Notez que dict supporte aussi __getitem__() et __len__(), mais est considéré comme un mapping plutôt qu'une séquence car les recherches utilisent des clés arbitraires immutable plutôt que des entiers.
Comparé à l'ancien glossaire de ArcGIS Resources, maintenant renommé GIS Dictionary et hébergé chez Esri Support, le Python Glossary est assez substantiel. Cela dit, le Python Glossary est aussi un de ceux qui a du sens pour les personnes qui connaissent déjà la réponse, mais il peut être un peu difficile pour les personnes nouvelles dans le langage.
En regardant l'extrait du glossaire ci-dessus, on peut déduire que quelques méthodes spéciales/magiques/dunder sont très importantes pour l'itération : __iter__(), __getitem__(), et next() (ou __next__() si on travaille en Python 3.x). Il y a aussi quelques fonctions intégrées importantes qui interagissent avec ces méthodes : iter() et next(). Et enfin, la boucle for et l'instruction yield. Il y a plus de méthodes, fonctions, instructions et structures de contrôle impliquées dans l'itération, mais celles mentionnées sont centrales à toute discussion. Pour les lecteurs intéressés à en apprendre plus sur les itérateurs, générateurs, séquences, etc... ; il existe de nombreux primers et tutoriels déjà écrits et accessibles rapidement via une recherche Google.
Les listes sont si courantes en Python, et les nouveaux venus dans le langage y sont exposés si tôt, que j'utiliserai des exemples de listes Python pour le contexte aux côtés des exemples de curseurs de recherche ArcPy Data Access. Le Python Glossary indique qu'une liste est "une séquence Python intégrée," et une séquence est "un iterable qui supporte un accès efficace aux éléments en utilisant des indices entiers...." La documentation ArcPy Data Access SearchCursor indique que le curseur de recherche "retourne un itérateur de tuples." Puisque les itérateurs sont aussi itérables, on a l'impression que les fonctions intégrées et expressions couramment utilisées pour manipuler les listes peuvent aussi être utilisées avec les curseurs ArcPy.
Bien qu'on puisse utiliser la fonction intégrée dir() pour tenter de retourner une liste d'attributs valides pour un objet, je vais éviter d'inspecter les objets de cette manière car cela introduirait du désordre avec tous les attributs qui ne sont pas liés à l'itération. À la place, je vais m'appuyer sur la fonction intégrée isinstance() ainsi que sur les classes abstraites de base (ABCs) intégrées pour examiner les traits d'itération.
<SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> <SPAN class="comment token">#importer les ABCs pertinents depuis le module collections</SPAN>
<span class='operator token'>>></span><span class='operator token'>></span> from collections import Iterable, Iterator, Sequence
<span class='operator token'>>></span><span class='operator token'>></span>
<span class='operator token'>>></span><span class='operator token'>></span> <span class='comment token'>#créer une liste exemple et arcpy.da.SearchCursor</span>
<span class='operator token'>>></span><span class='operator token'>></span> l = [10, 20, 30, 40, 50]
<span class='operator token'>>></span><span class='operator token'>></span> cur = arcpy.da.SearchCursor(fc,["OID@", "SHAPE@"])
<span class='operator token'>>></span><span class='operator token'>></span>
<span class='operator token'>>></span><span class='operator token'>></span> <span class='comment token'>#examiner les traits d'itération des objets exemples</span>
<span class='operator token'>>></span><span class='operator token'>></span> abcs = (Iterable, Iterator, Sequence)
<span class='operator token'>>></span><span class='operator token'>></span> [isinstance(l, abc) for abc in abcs]
[True, False, True] <span class='comment token'>#Iterable, pas Iterator, Sequence</span>
<span class='operator token'>>></span><span class='operator token'>></span>
<span class='operator token'>>></span><span class='operator token'>></span> <SPAN class="punctuation token">[</SPAN>isinstance<SPAN class="punctuation token">(</SPAN>cur<SPAN class="punctuation token">,</SPAN> abc<SPAN class="punctuation token">)</SPAN> <SPAN class="keyword token">pour</SPAN> abc <SPAN class="keyword token">dans</SPAN> abcs<SPAN class="punctuation token">]</SPAN>
<SPAN class="punctuation token">[</SPAN><SPAN class="token boolean">Vrai</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="token boolean">Vrai</SPAN><SPAN class="punctuation token">,</SPAN> <SPAN class="token boolean">Faux</SPAN><SPAN class="punctuation token">]</SPAN> <SPAN class="comment token">#Iterable, Iterator, pas Sequence</SPAN>
<SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN>
<SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> <SPAN class="comment token">#regarder les types pour les objets d'exemple et les itérateurs des objets d'exemple</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> type<SPAN class="punctuation token">(</SPAN>l<SPAN class="punctuation token">)</SPAN>
<SPAN class="operator token"><</SPAN>type <SPAN class="string token">'list'</SPAN><SPAN class="operator token">></SPAN>
<SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> type<SPAN class="punctuation token">(</Span>it_l<Span class="punctuation token">)</Span>
<Span class="operator token"><</Span>type <Span class="string token">'listiterator'</Span><Span class="operator token">></Span>
<Span class="operator token">>></Span><Span class="operator token">></Span>
<Span class="operator token">>></Span><Span class="operator token">></Span> it_cur <Span class="operator token">=</Span> iter<Span class="punctuation token">(</Span>cur<Span class="punctuation token">)</Span>
<Span class="operator token">>></Span><Span class="operator token">></Span> type<Span class="punctuation token">(</Span>cur<Span class="punctuation token">)</Span>
<Span class="operator token"><</Span>type <Span class="string token">'da.SearchCursor'</Span><Span class="operator token">></Span>
<Span class="operator token">>></Span><Span class="operator token">></Span> type<Span class="punctuation token">(</span>it_cur<span class="punctuation token"> )</span>
<span class="operator token"><</span>type <span class="string token">'da.SearchCursor'</span><span class="operatortoken">></span>
<spanclass="operatortoken">>></span><spanclass="operatortoken">></span>
<spanclass="operatortoken">>></span><spanclass="commenttoken">#regarder l'identit des objets curseur</span>
<spanclass="operatortoken">>></span><spanclass="operatortoken">></span> id<spanclass="punctuationtoken">(</span>cur<spanclass="punctuationtoken"> )</span>
<spanclass="numbertoken">26866224</span>
<spanclass="operatortoken"> >></span><span class= "operator token"> ></span> id<span class= "punctuation token"> (</span>it_cur<span class= "punctuation token"> )</span>
<span class= "number token"> 262686224</span>
<span class= "operator token">
<span></span></span><span></span></span><span></span></span><span></span></span><span></span></span><span></span>
Comme on peut le voir ci-dessus, ce qui démontre essentiellement ce qui est indiqué dans le Glossaire Python, une liste est à la fois un iterable et une séquence mais pas un iterator tandis qu'un ArcPy Data Access search cursor est à la fois un iterable et un iterator mais pas une séquence. Des lignes 20-21, nous voyons que l'appel de iter() sur une liste renvoie un nouveau type d'objet ainsi qu'un nouvel objet, c'est-à-dire le listiterator. Des lignes 26-27, nous voyons que l'appel de iter() sur un search cursor renvoie un search cursor au lieu d'un nouvel objet iterator. Non seulement un search cursor est renvoyé par l'appel de iter(), mais les lignes 30-33 montrent que le même objet search cursor est renvoyé lors de cet appel. Ce modèle de conception où un iterable est son propre iterator est assez courant en Python.
Dans le prochain article de cette série, nous irons au-delà des composants de l'itération et commencerons réellement à itérer sur des objets Python, y compris les cursors ArcPy Data Access.