カーソルとは、テーブルの行セットの反復処理やテーブルへの新しい行の挿入に使用できるデータ アクセス オブジェクトです。カーソルには、検索、挿入、または更新の 3 つの形態があります。カーソルは一般に、既存のジオメトリの読み取りおよび新しいジオメトリの書き込みのために使用されます。
それぞれのカーソルのタイプは、対応する ArcPy 関数 (SearchCursor、InsertCursor、または UpdateCursor) によって、テーブル、テーブル ビュー、フィーチャクラス、またはフィーチャ レイヤー上で作成されます。検索カーソルは、行を取得するために使用できます。更新カーソルは行をカーソル位置で更新および削除するために使用でき、挿入カーソルはテーブルまたはフィーチャクラスに行を挿入するために使用されます。
カーソル | 説明 |
---|---|
arcpy.da.InsertCursor(in_table, field_names) | 行を挿入します。 |
arcpy.da.SearchCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause}) | 読み取り専用でアクセスします。 |
arcpy.da.UpdateCursor(in_table, field_names, {where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause}) | 行を更新または削除します。 |
カーソル | 説明 |
---|---|
arcpy.InsertCursor(dataset, {spatial_reference}) | 行を挿入します。 |
arcpy.SearchCursor(dataset, {where_clause}, {spatial_reference}, {fields}, {sort_fields}) | 読み取り専用でアクセスします。 |
arcpy.UpdateCursor(dataset, {where_clause}, {spatial_reference}, {fields}, {sort_fields}) | 行を更新または削除します。 |
これらのカーソルは順方向にのみ進むことができます。逆方向に進んで、すでに取得した行を取得することはできません。データへの複数のパスが必要となるスクリプトでは、カーソルの reset メソッドを呼び出します。
検索カーソルと更新カーソルは、for ループを使用して反復処理できます。次の行にアクセスするには、Python の内蔵の next メソッドを明示的に使用して次行を返す方法もあります。カーソルに対して next メソッドを使用して、N 個の行が含まれているテーブルの行すべてを取得するには、next を N 回呼び出す必要があります。結果セットの最終行を取得した後で next を呼び出すと、StopIteration 例外が返されます。
import arcpy
cursor = arcpy.da.SearchCursor(fc, ['fieldA', 'fieldB'])
for row in cursor:
print(row)
検索カーソルと更新カーソルは with ステートメントもサポートしています。
import arcpy
with arcpy.da.SearchCursor(fc, ['fieldA', 'fieldB']) as cursor:
for row in cursor:
print(row)
テーブルから取得する各行は、フィールド値のリストとして返されます。その際、カーソルの field_names 引数に指定した順序でフィールド値が返されます。カーソルの fields プロパティを使用して、フィールド値の順序を確認することもできます。
カーソル オブジェクト
SearchCursor、UpdateCursor、および InsertCursor は、レコードの反復処理で使用できるカーソル オブジェクトを作成します。さまざまなカーソル関数によって作成されるカーソル オブジェクトのメソッドは、作成されるカーソルのタイプによって異なります。
各カーソル タイプがサポートしているメソッドは次のとおりです。
カーソル タイプ | メソッド | 位置への影響 |
---|---|---|
arcpy.da.SearchCursor | reset() | カーソルをその開始位置にリセットする |
arcpy.da.InsertCursor | insertRow() | テーブルに行を挿入する |
arcpy.da.UpdateCursor | updateRow() | 現在の行を更新する |
deleteRow() | テーブルから行を削除する | |
reset() | カーソルをその開始位置にリセットする |
insertRow
挿入カーソルは、新しい行を作成し、挿入するために使用されます。このカーソルを作成した後、insertRow メソッドを使用して、新規行を構成する値のリスト (タプル) を挿入します。カーソルで指定されていない (テーブル内の) フィールドには、そのフィールドのデフォルト値が割り当てられます。
import arcpy
# Create insert cursor for table
#
cursor = arcpy.da.InsertCursor("c:/base/data.gdb/roads_lut",
["roadID", "distance"])
# Create 25 new rows. Set the initial row ID and distance values
#
for i in range(0,25):
cursor.insertRow([i, 100])
updateRow
updateRow メソッドは、更新カーソルの現在位置にある行を更新するために使用します。カーソル オブジェクトから行を取得した後、その行を必要に応じて変更し、updateRow を呼び出して変更した行を渡すことができます。
import arcpy
# Create update cursor for feature class
#
with arcpy.da.UpdateCursor("c:/base/data.gdb/roads",
["roadtype", "distance"]) as cursor:
for row in cursor:
# Update the values in the distance field by multiplying
# the roadtype by 100. Road type is either 1, 2, 3 or 4.
#
row[1] = row[0] * 100
cursor.updateRow(row)
deleteRow
deleteRow メソッドは、更新カーソルの現在位置にある行を削除するために使用します。行を取得した後、更新カーソルの deleteRow を呼び出して対象行を削除します。
import arcpy
# Create update cursor for feature class
#
with arcpy.da.UpdateCursor("c:/base/data.gdb/roads",
["roadtype"]) as cursor:
# Delete all rows that have a roads type of 4
#
for row in cursor:
if row[0] == 4:
cursor.deleteRow()
フィールド値の参照と設定
各カーソルで使用するフィールドは、フィールド名のリスト (タプル) として指定します。カーソルから行を取得する場合、それらの行は、インデックス位置に対応するフィールド値のリストとして返されます。
次の例では、位置を指定して州名と人口数にアクセスします。
import arcpy
fc = "c:/base/data.gdb/USA/States"
# Use SearchCursor to access state name and the population count
#
with arcpy.da.SearchCursor(fc, ['STATE_NAME', 'POP2000']) as cursor:
for row in cursor:
# Access and print the row values by index position.
# state name: row[0]
# population: row[1]
#
print('{} has a population of {}'.format(row[0], row[1]))
フィールド名の代わりに、ショートカットとしてトークンを使用することもできます。どのテーブルにも ObjectID フィールドがあります。このフィールドには、データ タイプに応じてさまざまな名前を割り当てることができます。単純なフィーチャクラスにはジオメトリ フィールドが必要です。このフィールドには、(必ずではありませんが) 通常、Shape という名前が付けられます。ObjectID フィールドにアクセスするには OID@ トークンを使用します。(ジオメトリ オブジェクトを返す)SHAPE@ トークンを使用すれば、事前にフィールド名がわからなくても、フィーチャクラスのジオメトリ フィールドにアクセスできます。
マルチポイント フィーチャクラスの検索カーソル
import arcpy
infc = arcpy.GetParameterAsText(0)
# Enter for loop for each feature
#
for row in arcpy.da.SearchCursor(infc, ["OID@", "SHAPE@"]):
# Print the current multipoint's ID
#
print("Feature {}:".format(row[0]))
# For each point in the multipoint feature,
# print the x,y coordinates
#
for pnt in row[1]:
print("{}, {}".format(pnt.X, pnt.Y))
その他のジオメトリ トークンを使用して、特定のジオメトリ情報にアクセスできます。完全なジオメトリにアクセスするのはかなり時間がかかります。ジオメトリの特定のプロパティのみが必要な場合は、ショートカットとなるトークンを使用してジオメトリのプロパティにアクセスしてください。たとえば、SHAPE@XY は、フィーチャの重心を表す X 座標と Y 座標の組み合わせを返します。
カーソルおよびロック
挿入カーソルおよび更新カーソルは、ArcGIS アプリケーションによって設定されたテーブル ロックが適用されます。ロックは、複数のプロセスが同時に同じテーブルを変更しないようにする機能です。ロックには、共有と排他の 2 種類があります。
- 共有ロックは、テーブルまたはデータセットにアクセスするときにいつでも適用されます。テーブルに対して複数の共有ロックが存在できますが、共有ロックが存在する場合に排他ロックを適用することはできません。たとえば、ArcMap でフィーチャクラスを表示するときや、ArcCatalog でテーブルをプレビューするときに、共有ロックが適用されます。
- 排他ロックは、テーブルまたはフィーチャクラスに対して変更が行われるときに適用されます。たとえば、ArcMap でフィーチャクラスを編集して保存するときや、ArcCatalog でテーブルのスキーマを変更するとき、または Python IDE (PythonWin など) でフィーチャクラスに対して挿入カーソルを使用するときに、排他ロックが ArcGIS によって適用されます。
テーブルまたはフィーチャクラスに対して排他ロックが存在する場合に、そのデータセットに対して更新カーソルおよび挿入カーソルを作成することはできません。UpdateCursor 関数または InsertCursor 関数は、データセットに対して排他ロックが設定されていると失敗します。これらの関数によってカーソルが正常に作成されると、同じデータセットに対して 2 つのスクリプトが更新カーソルまたは挿入カーソルを作成できないように、排他ロックがデータセットに適用されます。
Python では、カーソルが解放されるまでロックが持続します。このようにしなければ、他のすべてのアプリケーションやスクリプトのデータセットへのアクセスを不必要に禁止する可能性があります。次のいずれかの場合にカーソルが解放されます。
- with ステートメント内にカーソルを追加する。これによって、そのカーソルが正常に完了するかどうかにかかわらずロックが解除されます。
- カーソルに対して reset() を呼び出す。
- カーソルが完了する。
- Python の del ステートメントを使用して、カーソルを明示的に削除する。
ArcMap の編集セッションは、編集セッションの実行中にデータに共有ロックを適用します。編集内容を保存するときには、排他ロックが適用されます。排他ロックがすでに存在する場合には、データセットは編集できません。
カーソルと BLOB フィールド
BLOB (Binary Large Object) は、長いバイナリ数値列として格納されるデータです。ArcGIS はアノテーションとディメンションを BLOB として格納します。また、このタイプのフィールドには、画像、マルチメディア、またはコードのビットなどのアイテムを格納することができます。カーソルを使用して、BLOB フィールドの内容を読み込んだり、表示したりできます。
Python では、文字列、bytearray、および memoryviews を BLOB フィールドで使用できます。BLOB フィールドを読み込むと、memoryview オブジェクトが返されます。
import arcpy
data = open("c:/images/image1.png", "rb").read()
ic = arcpy.da.InsertCursor("c:/data/fgdb.gdb/fc", ['imageblob'])
ic.insertRow([data])
import arcpy
sc = arcpy.da.SearchCursor("c:/data/fgdb.gdb/fc", ["imageblob"])
memview = sc.next()[0]
open("c:/images/image1_copy.png", "wb").write(memview.tobytes())