カーソルを使用したデータへのアクセス
カーソルとは、テーブルの行セットの反復処理やテーブルへの新しい行の挿入に使用できるデータ アクセス オブジェクトです。カーソルには、検索、挿入、または更新の 3 つの形態があります。カーソルは一般に、既存のジオメトリの読み取りおよび新しいジオメトリの書き込みのために使用されます。
それぞれのカーソルのタイプは、対応する 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}) |
行を更新または削除します。 |
注意:カーソルはレイヤ/テーブル ビューで定義されたクエリと選択を反映します。カーソル オブジェクトには、操作中にジオプロセシング ツールにで使用される行のみが格納されます。
3 つのカーソル関数すべてがカーソル オブジェクトを作成し、このオブジェクトを使用して行オブジェクトにアクセスできます。行オブジェクトがサポートするメソッドは、作成されるカーソルのタイプによって異なります。
これらのカーソルは順方向のみに進むことができます。逆方向に進んですでに取得した行を取得したり、データに対して複数回のパスを実行したりすることはできません。スクリプトでデータに対して複数回のパスを実行する必要がある場合は、カーソル関数を再実行する必要があります。同じ編集セッション内で(または適切な分離レベルのデータベース トランザクション内で)2 つのカーソル関数が実行された場合、同時に実行されている他のアプリケーションでデータを変更してもアプリケーションは影響を受けません。
検索カーソルまたは更新カーソルは For ループまたは While ループによって反復でき、カーソルの next メソッドを使用して次の行を返すことができます。カーソルに対して next メソッドを使用して、N 個の行が含まれているテーブルの行すべてを取得するには、next を N 回呼び出す必要があります。結果セットの最後の行が取得された後に next を呼び出すと、None が返されます。これは Python データ タイプの 1 つで、ここではプレースホルダの役割を果たします。
次の例は、シンプルなカーソル操作を示しています。フィーチャクラスの行ごとに、各 String フィールドの名前と値を出力します。
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 の各関数は、レコードの反復処理に使用できるカーソル オブジェクト(列挙オブジェクトとも呼ばれる)を作成します。さまざまなカーソル関数によって作成されるカーソル オブジェクトのメソッドは、作成されるカーソルのタイプによって異なります。
次の図に、それぞれのカーソル タイプでサポートするメソッドを示します。
|
カーソル タイプ |
メソッド |
位置への影響 |
|---|---|---|
|
Search |
next |
次の行オブジェクトを取得する |
|
Insert |
newRow |
空の行オブジェクトを作成する |
|
insertRow |
テーブルに行オブジェクトを挿入する |
|
|
next |
次の行オブジェクトを取得する |
|
|
Update |
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
行のフィールド値を取得および設定するためには 2 つの基本的な方法があります。
- フィールド名を使用する(例: value = row.road_type)
- getValue および setValue を使用する(例: value = row.getValue("road_type"))
|
メソッド |
説明 |
|---|---|
|
getValue(field_name) |
フィールド値を取得します。 |
|
isNull(field_name) |
フィールド値が NULL であるかどうか検査します。 |
|
setNull(field_name) |
フィールド値を NULL に設定します。 |
|
setValue(field_name, object) |
フィールド値を設定します。 |
次に示すサンプルでは、ワークスペース内にあるポリゴン フィーチャクラスすべてのルックアップ テーブルを作成します。このルックアップ テーブルには、フィーチャクラス内の各フィーチャの ObjectID に対応する ID、および [バッファ(Buffer)] ツールのために使用できる距離の値が格納されます。
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 アプリケーションによって設定されたテーブル ロックが適用されます。ロックは、複数のプロセスが同時に同じテーブルを変更しないようにする機能です。ロックには、共有および排他の 2 種類があります。
- 共有ロックは、テーブルまたはデータセットにアクセスするときにいつでも適用されます。テーブルに対して複数の共有ロックが存在できますが、共有ロックが存在する場合に排他ロックを適用することはできません。たとえば、ArcMap でフィーチャクラスを表示するときや、ArcCatalog でテーブルをプレビューするときに、共有ロックが適用されます。
- 排他ロックは、テーブルまたはフィーチャクラスに対して変更が行われるときに適用されます。たとえば、ArcMap でフィーチャクラスを編集して保存するときや、ArcCatalog でテーブルのスキーマを変更するとき、または Python IDE(PythonWin など)でフィーチャクラスに対して挿入カーソルを使用するときに、排他ロックが ArcGIS によって適用されます。
テーブルまたはフィーチャクラスに対して排他ロックが存在する場合に、そのデータセットに対して更新カーソルおよび挿入カーソルを作成することはできません。UpdateCursor 関数または InsertCursor 関数は、データセットに対して排他ロックが設定されていると失敗します。これらの関数によってカーソルが正常に作成されると、同じデータセットに対して 2 つのスクリプトが更新カーソルまたは挿入カーソルを作成できないように、排他ロックがデータセットに適用されます。
アプリケーションまたはスクリプトがカーソル オブジェクトを明示的に解放または閉じることによってデータセットを解放するまで、ロックは存続します。スクリプト内では、データセットに対して適用した排他ロックを解放するために、カーソル オブジェクトを削除する必要があります。このようにしなければ、他のすべてのアプリケーションやスクリプトのデータセットへのアクセスを不必要に禁止する可能性があります。次のサンプルでは、更新カーソルをオープンし、解放する方法を示しています。テーブルに別の排他ロックが適用されているために 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 の編集セッションは、編集セッションの実行中にデータに共有ロックを適用します。編集内容を保存するときには、排他ロックが適用されます。排他ロックがすでに存在する場合には、データセットは編集できません。
PythonWin などの Python エディタを使用する際には、カーソルによって設定されたデータセット ロックを解除するためにオブジェクト参照をクリーンアップする必要が生じることがあります。使用されていないオブジェクトを削除したり、スクリプト内の参照を明示的に削除したりする時期を制御するには、gc(ガーベッジ コレクション)モジュールを使用します。