<\/HEAD>
Dies ist der erste Teil einer mehrteiligen Serie über ArcPy-Cursor; insbesondere die Arbeit mit ArcPy-Cursor als iterierbare Objekte in Python. Der erste Teil der Serie<\/STRONG> behandelt einige der wichtigen Komponenten der Iteration in Python. Der zweite Teil der Serie<\/A> behandelt das Iterieren und Schleifen über ArcPy Data Access-Cursor. Der dritte Teil der Serie<\/A> behandelt die Verwendung mehrerer Python-eigener und itertools-Funktionen mit ArcPy Data Access-Cursor. Der vierte Teil der Serie wird sich mit der Verwendung von Generatoren oder Generatorausdrücken befassen, um Auswahl- oder Filterlogik für die Wiederverwendung von Code zu trennen. Fünfte oder folgende Teile sind derzeit unbekannt.<\/EM><\/P><\/P>
Diese und die folgenden Blogbeiträge konzentrieren sich auf
ArcPy Data Access<\/A>-Cursor im Kontext der Iteration, daher der Titel der Serie. Es mag zwar albern erscheinen, über iterierbare Cursor zu sprechen, da ein Cursor ohne Iteration im Grunde wertlos ist, aber meine Erfahrung beim Skripten mit ArcPy-Cursor und bei der Beantwortung von Fragen auf GeoNet hat mich motiviert, einige pythonische Denkweisen und Arbeitsweisen mit Cursor zu teilen.<\/P><\/P>
Beim Sprechen über Iteration in Python gibt es zahlreiche Begriffe und Ausdrücke, die für eine Diskussion relevant sein können. Fünf Begriffe, die ich für besonders wichtig und relevant für diese Blogserie halte, sind:<\/P>
Glossar<\/A><\/SPAN><\/P>generator<\/STRONG><\/P>Eine Funktion, die einen Iterator zurückgibt. Sie sieht aus wie eine normale Funktion, enthält jedoch
yield<\/SPAN> <\/A>-Anweisungen zur Erzeugung einer Reihe von Werten, die in einer for-Schleife verwendet werden können oder einzeln mit der next()<\/A><\/SPAN>-Funktion abgerufen werden können. Jedes yield<\/SPAN> <\/A>setzt die Verarbeitung vorübergehend aus und merkt sich den Ausführungszustand (einschließlich lokaler Variablen und ausstehender try-Anweisungen). Wenn der Generator fortgesetzt wird, setzt er an der Stelle fort, an der er aufgehört hat (im Gegensatz zu Funktionen, die bei jedem Aufruf neu starten).<\/P><\/P>generator expression<\/STRONG><\/P>Ein Ausdruck, der einen Iterator zurückgibt. Er sieht aus wie ein normaler Ausdruck, gefolgt von einem for<\/SPAN> <\/A>-Ausdruck, der eine Schleifenvariable, einen Bereich und optional einen if<\/A><\/SPAN>-Ausdruck definiert. Der kombinierte Ausdruck erzeugt Werte für eine umschließende Funktion:<\/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\"># Summe der Quadrate 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>
Ein Objekt, das seine Mitglieder einzeln zurückgeben kann. Beispiele für Iterables sind alle Sequenztypen (wie
list< \/A>, str< \/A>, und tuple< \/A>) sowie einige Nicht-Sequenztypen wie dict< \/A> und iter()-Funktion oder verwenden Sie sie in einer for-Schleife. Der Versuch, dies mit einem Iterator zu tun, gibt einfach dasselbe erschöpfte Iterator-Objekt zurück, das im vorherigen Iterationsdurchlauf verwendet wurde, wodurch es wie ein leerer Container erscheint.
sequence
Ein iterable , das effizienten Elementzugriff mittels ganzzahliger Indizes über die spezielle Methode __getitem__() unterstützt und eine len()-Methode definiert, die die Länge der Sequenz zurückgibt. Einige eingebaute Sequenztypen sind list, str, tuple und unicode. Beachten Sie, dass dict ebenfalls __getitem__() und __len__() unterstützt, aber als Mapping betrachtet wird und nicht als Sequenz, da die Nachschlagevorgänge beliebige immutable Schlüssel anstelle von Ganzzahlen verwenden.
Im Vergleich zum alten Glossar von ArcGIS Resources, jetzt umbenannt in GIS Dictionary und untergebracht bei Esri Support, ist das Python Glossary ziemlich umfangreich. Das Python Glossary ist jedoch auch eines jener, das für Menschen Sinn macht, die die Antwort bereits kennen, aber für Neueinsteiger in die Sprache etwas schwer zugänglich sein kann.
Beim Betrachten des obigen Glossarauszugs erkennt man, dass einige spezielle/magische/dunder Methoden für die Iteration sehr wichtig sind: __iter__(), __getitem__() und next() (oder __next__(), wenn man mit Python 3.x arbeitet). Es gibt auch einige wichtige eingebaute Funktionen, die mit diesen Methoden interagieren: iter() und next(). Und nicht zuletzt die for-Schleife und die yield-Anweisung. Es gibt noch weitere Methoden, Funktionen, Anweisungen und Kontrollstrukturen, die mit Iteration zu tun haben, aber die genannten sind zentral für jede Diskussion. Für Leser, die mehr über Iteratoren, Generatoren, Sequenzen usw. lernen möchten, gibt es zahlreiche Einführungen und Tutorials, die bereits geschrieben wurden und nur eine schnelle Google-Suche entfernt sind.
Listen sind in Python so verbreitet und Neueinsteiger in die Sprache kommen so früh damit in Berührung, dass ich Python-Listenbeispiele im Kontext zusammen mit den ArcPy Data Access SearchCursor-Beispielen verwenden werde. Das Python Glossary besagt, dass eine Liste "eine eingebaute Python-Sequenz" ist und eine Sequenz "ein iterable ist, das effizienten Elementzugriff mittels ganzzahliger Indizes unterstützt...“. Die ArcPy Data Access SearchCursor -Dokumentation besagt, dass der Suchcursor "einen Iterator von Tupeln zurückgibt." Da Iteratoren ebenfalls iterable sind, bekommt man den Eindruck, dass eingebaute Funktionen und Ausdrücke, die üblicherweise zur Manipulation von Listen verwendet werden, auch mit ArcPy-Cursorn verwendet werden können.
Obwohl man die eingebaute dir()-Funktion verwenden kann, um zu versuchen, eine Liste gültiger Attribute für ein Objekt zurückzugeben, werde ich darauf verzichten, die Objekte auf diese Weise zu inspizieren, da dies Unordnung durch alle Attribute verursachen würde, die nichts mit Iteration zu tun haben. Stattdessen werde ich mich auf die eingebaute isinstance()-Funktion zusammen mit eingebauten abstrakten Basisklassen (ABCs) verlassen, um Iterationseigenschaften zu betrachten.
>>>
>>> #betrachte Iterationseigenschaften der Beispielobjekte
>>> abcs = (Iterable, Iterator, Sequence)
>>> [isinstance(l, abc) for abc in abcs]
[True, False, True] #Iterable, nicht Iterator, Sequence
>>>
>>> [isinstance(cur, abc) für abc in abcs]
[True, True, False] #Iterable, Iterator, nicht Sequence
>>>
>>> #betrachte die Typen von Beispielobjekten und Iteratoren von Beispielobjekten
>>> it_l = iter(l)
>>> type(l)
<type 'list'>
>>> type(it_l)
<type 'listiterator'>
≫≫≫
≫≫≫ it_cur = iter(cur)
≫≫≫ type(cur)
<type 'da.SearchCursor'>
≫≫≫ type(it_cur)
<type 'da.SearchCursor'>
≫≫≫
≫≫≫ #betrachte die Identität der Cursor-Objekte
≫≫≫ id(cur)
262686224
≫≫≫ id(it_cur)
262686224
≫≫≫
</ Span >< Span >< < EM OJ I _ 29 > > </ Span >< Span >< < EM OJ I _ 30 > > </ Span >< Span >< < EM OJ I _ 31 > > </ Span >< Span >< < EM OJ I _ 32 > > </ Span >< Span >< < EM OJ I _ 33 > > </ Span ></ span ><SPAN class="operator token">>></SPAN><SPAN class="operator token">></SPAN> <SPAN class="comment token">#importiere relevante ABCs aus dem collections-Modul</SPAN>
<span class='operator token'>>></span><span class='operator token'>></span> from collections import Iterable<span class='punctuation token'>,</span> Iterator<span class='punctuation token'>,</span> 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'>#erstelle eine Beispiel-Liste und arcpy.da.SearchCursor</span>
<span class='operator token'>>></span><span class='operator token'>></span> l = [10<span class='punctuation token'>,</span> 20<span class='punctuation token'>,</span> 30<span class='punctuation token'>,</span> 40<span class='punctuation token'>,</span> 50]
<span class='operator token'>>></span><span class='operator token'>></span> cur = arcpy.da.SearchCursor(fc<span class='punctuation token'>,[</span>"OID@"<span class='punctuation token'>,</span> "SHAPE@"])
Wie oben zu sehen ist, was im Grunde das demonstriert, was im Python Glossar angegeben ist, ist eine Liste sowohl ein Iterable als auch eine Sequenz, aber kein Iterator, während ein ArcPy Data Access Search Cursor sowohl ein Iterable als auch ein Iterator, aber keine Sequenz ist. Aus den Zeilen 20-21 sehen wir, dass der Aufruf von iter() </ SPan > auf einer Liste einen neuen Objekttyp sowie ein neues Objekt zurückgibt, d.h. den listiterator </ SPan > Aus den Zeilen 26-27 sehen wir, dass der Aufruf von iter() </ SPan > auf einem Search Cursor einen Search Cursor anstelle eines neuen Iterator-Objekts zurückgibt. Nicht nur wird durch den Aufruf von iter() </ SPan > ein Search Cursor zurückgegeben, sondern die Zeilen 30-33 zeigen, dass dasselbe Search Cursor-Objekt zurückgegeben wird. Dieses Entwurfsmuster, bei dem ein Iterable sein eigener Iterator ist, ist in Python ziemlich üblich.
Im nächsten Beitrag dieser Serie werden wir über die Komponenten der Iteration hinausgehen und tatsächlich über Python-Objekte iterieren, einschließlich ArcPy Data Access Cursors.