python使用遊標訪問數據
遊標是一種數據訪問對象,可用於在表中叠代一組行或者向表中插入新行。遊標有三種形式:搜索、插入或更新。遊標通常用於讀取現有幾何和寫入新幾何。
每種類型的遊標均由對應的 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(垃圾收集)模塊來控制何時刪除未使用對象和/或明確刪除腳本中的引用。
python使用遊標訪問數據