Zugreifen auf Daten mit Cursorn

Ein Cursor ist ein Datenzugriffsobjekt, mit dem entweder die Zeilen in einer Tabelle durchlaufen oder neue Zeilen in eine Tabelle eingefügt werden können. Cursor können in drei Formen auftreten: als Such-, Einfüge- oder Aktualisierungs-Cursor. Cursor werden im Allgemeinen dazu verwendet, bestehende Geometrie zu lesen und neue Geometrie zu schreiben.

Jeder Cursor-Typ wird durch eine entsprechende ArcPy-Funktion (SearchCursor, InsertCursor oder UpdateCursor) für eine Tabelle, eine Tabellensicht, eine Feature-Class oder einen Feature-Layer erstellt. Mit einem Such-Cursor können Zeilen abgerufen werden. Mit einem Aktualisierungs-Cursor können Zeilen positionsabhängig aktualisiert und gelöscht werden. Mit einem Einfüge-Cursor können Sie Zeilen in eine Tabelle oder Feature-Class einfügen.

Cursor

Erläuterung

InsertCursor(dataset, {spatial_reference})

Fügt Zeilen ein.

SearchCursor(dataset, {where_clause}, {spatial_reference}, {fields}, {sort_fields})

Schreibgeschützter Zugriff

UpdateCursor(dataset, {where_clause}, {spatial_reference}, {fields}, {sort_fields})

Aktualisiert oder löscht Zeilen.

Cursorfunktionen

HinweisHinweis:

Cursor berücksichtigen Definitionsabfragen und Auswahlen in Layern und Tabellensichten. Das Cursor-Objekt enthält nur die Zeilen, die von allen Geoverarbeitungswerkzeugen für Operationen verwendet werden.

Alle drei Cursorfunktionen erstellen ein Cursor-Objekt, das zum Zugreifen auf Zeilenobjekte verwendet werden kann. Welche Methoden vom Zeilenobjekt unterstützt werden, hängt vom Typ des erstellten Cursors ab.

Cursor können nur in Vorwärtsrichtung durchlaufen werden. Das Zurückkehren zu und Abrufen von bereits abgerufenen Zeilen oder mehrere Durchläufe durch die Daten werden nicht unterstützt. Wenn ein Skript die Daten mehrmals durchlaufen muss, muss die Anwendung die Cursorfunktion erneut ausführen. Wenn beide Ausführungen in derselben Editiersitzung (oder Datenbanktransaktion mit dem entsprechenden Isolationsgrad) erfolgen, ist sichergestellt, dass die Anwendung keine Änderungen an den Daten erkennt, die von anderen, gleichzeitig ausgeführten Anwendungen vorgenommen wurden.

Cursor für Suchen oder Aktualisierungen können mit der Schleife For oder in einer Schleife While durchlaufen werden, indem die next-Methode des Cursors zum Zurückgeben der nächsten Zeile verwendet wird. Wenn Sie die next-Methode eines Cursors verwenden, um alle Zeilen einer Tabelle mit N Zeilen abzurufen, muss das Skript N Aufrufe von next durchführen. Ein Aufruf von next nach dem Abrufen der letzten Zeile im Ergebnissatz gibt den Wert None zurück. Dabei handelt es sich um einen Python-Datentyp, der in diesem Fall als Platzhalter fungiert.

In diesem Beispiel wird eine einfache Cursor-Operation veranschaulicht. Für jede Zeile in einer Feature-Class wird der Name und Wert der einzelnen Zeichenfolgenfelder ausgegeben.

import arcpy

fc = "D:/st_johns/roads.shp"

# Create a search cursor 
#
rows = arcpy.SearchCursor(fc) 

# Create a list of string fields
fields = arcpy.ListFields(fc, "", "String")

for row in rows:
    for field in fields:
        if field.type != "Geometry":
            print "%s: Value = %s" % (field.name, row.getValue(field.name))

Alle aus einer Tabelle abgerufenen Zeilenobjekte enthalten logischerweise dieselbe Menge von Feldern in einer identischen Reihenfolge. Die Reihenfolge der Felder in einer Zeile einer Tabelle ist identisch mit der Reihenfolge der Felder, die von der Funktion ListFields zurückgegeben werden. Die Zeile enthält nur die sichtbaren Felder der Tabelle, für die der Cursor erstellt wurde, wobei jeder Feldname eine Eigenschaft des Objekts ist.

Cursor-Objekt

Die Funktionen SearchCursor, UpdateCursor und InsertCursor erstellen ein Cursor-Objekt (auch Enumerationsobjekt genannt), das zum Durchlaufen der Datensätze verwendet werden kann. Welche Methoden das von den verschiedenen Cursor-Funktionen erstellte Cursor-Objekt aufweist, hängt vom Typ des erstellten Cursors ab.

Im folgenden Diagramm werden die unterstützten Methoden für die einzelnen Cursor-Typen aufgeführt:

Cursor-Typ

Methode

Auswirkung auf Position

Suchen

next

Ruft das nächste Zeilenobjekt ab.

Einfügen

newRow

Erstellt ein leeres Zeilenobjekt.

insertRow

Fügt ein Zeilenobjekt in die Tabelle ein.

next

Ruft das nächste Zeilenobjekt ab.

Aktualisieren

updateRow

Aktualisiert die aktuelle Zeile mit einem geänderten Zeilenobjekt.

deleteRow

Entfernt eine Zeile aus der Tabelle.

next

Ruft das nächste Zeilenobjekt ab.

insertRow

Der Einfüge-Cursor wird verwendet, um neue Zeilen zu erstellen und diese einzufügen. Die grundlegende Vorgehensweise bei der Verarbeitung besteht darin, die newRow-Methode für das Cursor-Objekt zu verwenden, in das Zeilen eingefügt werden sollen. Dieses neue Zeilenobjekt enthält alle Felder der Tabelle. Sie können den Feldern der Zeilen Werte zuweisen, bevor Sie die Zeile mit insertRow einfügen.

import arcpy

# Create insert cursor for table
#
rows = arcpy.InsertCursor("D:/St_Johns/data.gdb/roads_lut")
x = 1

# Create 25 new rows. Set the initial row ID and distance values
#
while x <= 25:
    row = rows.newRow()
    row.rowid = x
    row.distance = 100
    rows.insertRow(row)
    x = x + 1

updateRow

Mit der updateRow-Methode kann die Zeile an der aktuellen Position eines Aktualisierungs-Cursors aktualisiert werden. Nach dem Abrufen eines Zeilenobjekts aus dem Cursor-Objekt ändern Sie die Zeile wie gewünscht und rufen updateRow auf, um die geänderte Zeile zu übergeben.

import arcpy

# Create update cursor for feature class
#
rows = arcpy.UpdateCursor("D:/St_Johns/data.gdb/roads")

for row in rows:
# Update the field used in buffer so the distance is based on the road
#   type. Road type is either 1, 2, 3, or 4. Distance is in meters.
#
    row.buffer_distance = row.road_type * 100
    rows.updateRow(row)

deleteRow

Mit der deleteRow-Methode kann die Zeile an der aktuellen Position eines Aktualisierungs-Cursors gelöscht werden. Sie rufen nach dem Abrufen des Zeilenobjekts deleteRow für den Cursor auf, um die Zeile zu löschen.

import arcpy

# Create update cursor for feature class
#
rows = arcpy.UpdateCursor("D:/St_Johns/data.gdb/roads")

for row in rows:
    # Delete all rows that have a roads type of 4
    if row.road_type == 4:
        rows.deleteRow(row)

getValue und setValue

Es gibt zwei grundlegende Möglichkeiten, die Feldwerte für eine Zeile abzurufen und festzulegen:

Methode

Erläuterung

getValue(field_name)

Ruft den Feldwert ab.

isNull(field_name)

Entspricht dem Feldwert Null.

setNull(field_name)

Legt den Feldwert auf Null fest.

setValue(field_name, object)

Legt den Feldwert fest.

Methoden für Zeilen

Im folgenden Beispiel wird eine Lookup-Tabelle für alle Polygon-Feature-Classes in einem Workspace erstellt. Die Lookup-Tabelle enthält eine ID, die der ObjectID für jedes Feature in der Feature-Class entspricht, sowie einen Entfernungswert, der für das Werkzeug Puffer verwendet werden kann.

import arcpy
from arcpy import env
import os

env.overwriteOutput = 1
env.workspace = arcpy.GetParameterAsText(0)

# List the polygon feature classes
#
fcs = arcpy.ListFeatureClasses("*","polygon")

# Loop through the results.
#
for fc in fcs:
   # Get the ObjectID field
   #
   desc = arcpy.Describe(env.workspace + os.sep + fc)
   OIDFieldName = desc.OIDFieldName

   # Create lookup table name
   #
   if fc.endswith(".shp"):
      tab = fc.replace(".", "_lut.")
   else:
      tab = fc + "_lut"

   # Create lookup table and add fields
   #
   arcpy.CreateTable_management(env.workspace, tab)
   arcpy.AddField_management(tab,"id","long")
   arcpy.AddField_management(tab,"dist","long")

   # Open insert cursor on new lookup table
   #
   tabcur = arcpy.InsertCursor(env.workspace + os.sep + tab)

   # Open search cursor on feature class
   #
   featcur = arcpy.SearchCursor(env.workspace + os.sep + fc)

   # Loop through the rows in the feature class
   #
   for f_row in featcur:
       # Create a new row for the lookup table and set its ID to be the
       #  same as the feature OID and set the distance to 100.
       #
       t_row = tabcur.newRow()
       t_row.id = f_row.getValue(OIDFieldName)
       t_row.dist = 100

       # Insert the row into the lookup table and get the next row
       #  from the feature class
       #
       tabcur.insertRow(t_row)

Cursor und Sperren

Einfüge- und Aktualisierungs-Cursor berücksichtigen Tabellensperren, die von ArcGIS-Anwendungen festgelegt werden. Sperren verhindern, dass eine Tabelle zu einem bestimmten Zeitpunkt von mehreren Prozessen gleichzeitig geändert wird. Es gibt zwei Typen von Sperren: gemeinsame Sperren und exklusive Sperren.

Aktualisierungs- und Einfüge-Cursor können für eine Tabelle oder eine Feature-Class nur erstellt werden, wenn für das betreffende Dataset keine exklusive Sperre vorliegt. Die Funktionen UpdateCursor oder InsertCursor schlagen aufgrund einer exklusiven Sperre des Datasets fehl. Wenn mit diesen Funktionen erfolgreich ein Cursor erstellt wird, wird eine exklusive Sperre für das Dataset festgesetzt, sodass immer nur ein Skript Aktualisierungs- oder Einfüge-Cursor für dasselbe Dataset erstellen kann.

Sperren werden beibehalten, bis die Anwendung oder das Skript das Dataset durch Schließen oder explizites Freigeben des Cursor-Objekts freigibt. In einem Skript muss das Cursor-Objekt gelöscht werden, damit die exklusive Sperre des Datasets freigegeben wird. Andernfalls werden alle anderen Anwendungen und Skripte unnötigerweise am Zugriff auf das betreffende Dataset gehindert. Im folgenden Beispiel wird veranschaulicht, wie ein Aktualisierungs-Cursor geöffnet und freigegeben wird. Im Fehlerhandler wird überprüft, ob ein Fehler für die Funktion "UpdateCursor" wegen einer anderen exklusiven Sperre für die Tabelle auftritt.

import arcpy

# Create update cursor for feature class
#
try:
    # The variables row and rows are initially set to None, so that they
    #  can be deleted in the finally block regardless of where (or if)
    #  script fails.
    #
    row, rows = None, None

    rows = arcpy.UpdateCursor("D:/St_Johns/data.mdb/roads")

    # Update the field used in buffer so the distance is based on the 
    #   road type. Road type is either 1, 2, 3 or 4. Distance is in meters.
    #
    for row in rows:
        row.buffer_distance = row.road_type * 100
        rows.updateRow(row)

except:
    if not arcpy.GetMessages() == "":
        arcpy.AddMessage(arcpy.GetMessages(2))

finally:
    # Regardless of whether the script succeeds or not, delete 
    #  the row and cursor
    #
    if row:
        del row
    if rows:
        del rows

In einer Editiersitzung in ArcMap wird eine freigegebene Sperre für Daten gesetzt. Beim Speichern der Änderungen wird eine exklusive Sperre gesetzt. Ein Dataset kann nicht bearbeitet werden, wenn bereits eine exklusive Sperre vorliegt.

Wenn Sie in einem Python-Editor wie PythonWin arbeiten, müssen Sie möglicherweise Objektbezüge bereinigen, um von Cursorn gesetzte Dataset-Sperren aufzuheben. Verwenden Sie das gc-Modul (Garbage Collection), um festzulegen, zu welchen Zeitpunkten nicht verwendete Objekte entfernt werden, und löschen Sie Bezüge explizit im Skript.

Verwandte Themen


7/10/2012