游標是一種數據訪問對象,可用於在表中迭代一組行或者向表中插入新行。游標有三種形式:搜索、插入或更新。游標通常用於讀取現有幾何和寫入新幾何。
每種類型的游標均由對應的 ArcPy 函數(SearchCursor、InsertCursor 或 UpdateCursor)在表、表格視圖、要素類或要素圖層上創建。搜索游標可用於檢索行。更新游標可用於根據位置更新和刪除行,而插入游標可用於向表或要素類中插入行。
| 游標 |
說明 |
|---|---|
| InsertCursor(dataset, {spatial_reference}) |
插入行 |
| SearchCursor(dataset, {where_clause}, {spatial_reference}, {fields}, {sort_fields}) |
只讀訪問 |
| UpdateCursor(dataset, {where_clause}, {spatial_reference}, {fields}, {sort_fields}) |
更新或刪除行 |
注:
游標遵循圖層/表格視圖定義查詢和選擇。游標對象僅包含任一地理處理工具在操作期間將使用到的行。
全部三個游標函數可創建用於訪問行對象的游標對象。行對象支持的方法取決於所創建游標的類型。
游標只能向前導航,它們不支持備份和檢索已經檢索過的行,或者多輪次通過數據。如果腳本需要多輪次通過數據,應用程序必須重新執行游標函數。如果兩次執行都是在同一編輯會話(或具有適當隔離級別的數據庫事務)中進行的,則應用程序將確保不會應用由同時執行的另一應用程序對數據所做的更改。
以迭代方式搜索或更新游標的方式有兩種:可通過 For 循環,或者通過 While 循環並使用游標的 next 方法返回下一行。如果要在游標上使用 next 方法來檢索行數為 N 的表中的所有行,腳本必須反復調用 next N 次。在檢索完結果集中的最后一行后調用 next 將返回 None,它是一種 Python 數據類型,此處用作占位符。
本例為一個簡單的游標操作。它將打印出要素類中每行各個字符串字段的名稱和值。
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))
從表中檢索到的所有行對象在邏輯上包含一組順序相同的字段。具體而言,即表中某行的字段順序與ListFields 函數返回的字段順序相同。行內僅包含表中用於創建游標的可見字段,每個字段名稱都是該對象的屬性。
游標對象
SearchCursor、UpdateCursor 和 InsertCursor 函數能夠創建可用於對記錄進行遍歷的游標對象(有時稱為枚舉對象)。由不同游標函數創建的游標對象的方法不同,具體取決於創建的游標類型。
下圖顯示的是各游標類型支持的方法:
| 游標類型 |
方法 |
對位置的影響 |
|---|---|---|
| 搜索 |
next |
檢索下一個行對象 |
| 插入 |
newRow |
創建空的行對象 |
| insertRow |
向表中插入行對象 |
|
| next |
檢索下一個行對象 |
|
| 更新 |
updateRow |
用經過修改的行對象更新當前行 |
| deleteRow |
從表中刪除行 |
|
| next |
檢索下一個行對象 |
insertRow
插入游標用於創建並插入新行。基本的處理流程是在要插入行的游標對象上使用 newRow 方法。新的行對象包含在表中找到的所有字段,並且在使用 insertRow 插入行之前可以為行中的字段分配值。
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
updateRow 方法用於對更新游標當前所在位置的行進行更新。從游標對象提取行對象后,可以根據需要對行進行修改,然后調用 updateRow 傳入修改后的行。
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
deleteRow 方法用於刪除更新游標當前所在位置的行。提取行對象后,可在游標上調用 deleteRow 刪除行。
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 和 setValue
有兩種基本方法可以獲取和設置行中的字段值:
- 使用字段名,例如 value = row.road_type
- 使用 getValue 和 setValue,例如 value = row.getValue("road_type")
| 方法 |
說明 |
|---|---|
| getValue(field_name) |
獲取字段值 |
| isNull(field_name) |
字段值為空嗎 |
| setNull(field_name) |
將字段值設置為空 |
| setValue(field_name, object) |
設置字段值 |
下例將為工作空間中的所有多邊形要素類創建查找表。該查找表包含與要素類中各要素 ObjectID 對應的 ID,以及可供緩沖工具使用的距離值。
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)
游標和鎖定
插入和更新游標遵循由 ArcGIS 應用程序設置的表鎖。鎖能夠防止多個進程同時更改同一個表。鎖有兩種類型 - 共享和排他。
- 只要訪問表或數據集就會應用共享鎖。同一表中可以存在多個共享鎖,但存在共享鎖時,將不允許存在排它鎖。應用共享鎖的示例包括:在 ArcMap 中顯示要素類時以及在 ArcCatalog 中預覽表時。
- 對表或要素類進行更改時,將應用排它鎖。在 ArcGIS 中應用排它鎖的示例包括:在 ArcMap 中編輯和保存要素類時;在 ArcCatalog 中更改表的方案時;或者在 Python IDE(例如 PythonWin)中在要素類上使用插入游標時。
如果數據集上存在排它鎖,則無法為表或要素類創建更新和插入游標。UpdateCursor 或InsertCursor 函數會因數據集上存在排它鎖而失敗。如果這些函數成功地創建了游標,它們將在數據集上應用排它鎖,從而使兩個腳本無法在同一數據集上創建更新和插入游標。
在應用程序或腳本釋放數據集(通過關閉或明確釋放游標對象)之前,鎖將一直存在。在腳本中,應刪除游標對象,以便釋放該游標對象設置在數據集上的排它鎖。否則,將會阻止所有其他應用程序或腳本訪問數據集,而這是毫無必要的。下面的示例顯示了如何打開並釋放更新游標。其中使用錯誤處理程序來檢測 UpdateCursor 函數是否因表中存在其他排它鎖而失敗。
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
ArcMap 中的編輯會話將在其會話期間對數據應用共享鎖。保存編輯內容時將應用排它鎖。已經存在排它鎖時,數據集是不可編輯的。
使用 Python 編輯器時(例如 PythonWin),可能需要清除對象引用以刪除由游標設置的數據集鎖。使用 gc(垃圾收集)模塊來控制何時刪除未使用對象和/或明確刪除腳本中的引用。
