ブログ記事を書くか、単にPythonの場で議論を始めるか迷っていました。しばらくブログに投稿していなかったので、前者を選びました。<\/EM><\/P>
<\/P>
ArcPy Data Access Walk関数(arcpy.da.Walk<\/SPAN>)は非常に頼りになる関数で、私はかなり頻繁に使っています。ArcPy Walk関数は、EsriがPython実装でうまくやった例です。設計目標が何だったかはわかりませんが、Pythonのos.walk関数の地理空間対応版を作ることが目的だったように思えます。名前は同じで、多くのパラメータも同じで、結果も似ています。ArcPyでこの長年のネイティブPython機能を模倣したのは成功だと思います。つまり、os.walkに慣れているユーザーは簡単にarcpy.da.Walkに移行できます。<\/P>
<\/P>
ArcPy Walk関数は好きですが、いくつか小さな問題があります。まずはドキュメントの問題、というかドキュメント不足です。Walk関数のパラメータの一つにdatatypeがあります。ドキュメントにはdatatypeで許容される引数一覧の表がありますが、データタイプ自体の説明はありません。データタイプ名を見るとほとんどが明白なので、Esriは説明不要と判断したのかもしれません。<\/P>
<\/P>
名前だけでは最初はわかりやすく見えても、ドキュメント不足は曖昧さや混乱を招きます。例えば、"FeatureClass"には何が含まれるのでしょう?ジオデータベース内のフィーチャクラスは含まれると当然思いますが、シェープファイルはどうでしょう?シェープファイルはフィーチャクラスでしょうか?Esriの世界では通常「はい」ですが必ずしもそうとは限りません。本当の謎は"Geo"データタイプで、これはシェープファイルを含みますがジオデータベース内のフィーチャクラスは含みません。フィーチャクラスは「geo」ではないのでしょうか?ライブラリやAPIにとってドキュメントは重要ですが、それが今日書く主な理由ではありません。<\/P>
<\/P>
私のお気に入りのArcPy Walkパターンの一つは、Python組み込みのnext()<\/SPAN>関数を一度呼び出してフォルダ内のシェープファイルやジオデータベース内のフィーチャクラス、またはフィーチャデータセット内のフィーチャクラスのリストを取得する方法です。<\/P>
>> workspace = #フォルダまたはジオデータベースまたはフィーチャデータセットへのパス
>>>
>>> _, _, filenames = next(arcpy.da.Walk(workspace, datatype="FeatureClass"))
>>> filenames
[u'canadwshed_p.shp', u'plots.shp']
>>>
>>> #またはフィーチャクラスやシェープファイルをループ処理
>>> for file in next(arcpy.da.Walk(workspace, datatype="FeatureClass"))[2]:
... print file
canadwshed_p.shp
plots.shp
>>>
<\/code><\/pre>
<\/P>
最初の例では、一時的なWorkspace Walkerオブジェクトを作成し、それを保持したり分解したりする必要がありません。二番目の例ではforループ内でnext()を呼ぶことで、一階層だけ興味がある場合に余分なループを省けます。<\/P>
<\/P>
人生の多くの場合と同様に、ジオデータベース内のフィーチャクラスやフォルダ内のシェープファイルをリストアップする方法は一つだけではありません。実際、ArcPy Walk関数はArcGIS 10.1 SP1で導入された新しい方法です。それ以前には、多くのArcPyリスト関数(ListDatasets, ListFeatureClasses, ListFiles, ListRasters, ListTables, および ListWorkspaces) や ArcPy の Describe 関数を使うことができました。私は使いやすさとPython組み込み機能との類似性からArcPy Walkを好む傾向があります。<\/P>
<\/P>
このブログ記事を書く主な理由は、ArcPy Walk関数がつまずく領域、つまりインメモリデータソースについて共有するためです。古い方法ではインメモリワークスペースでも動作しますが、ArcPy Walkではそうではありません。<\/P>
>> arcpy.CreateFeatureclass_management('in_memory', 'test_fc')
>>> arcpy.CreateTable_management('in_memory', 'test_tbl')
>>> arcpy.CreateRasterDataset_management('in_memory','test_rd')
>>>
>>> # ArcPy Walk を使用
>>> next(arcpy.da.Walk('in_memory'))[2]
[]
>>>
>>> # ArcPy リスト関数を使用
>>> arcpy.env.workspace = 'in_memory'
>>> arcpy.ListFeatureClasses()
[u'test_fc']
>>> arcpy.ListTables()
[u'test_tbl']
>>> arcpy.ListRasters()
[u'test_rd']
>>> arcpy.ListDatasets()
[u'test_rd']
>>>
>>> # ArcPy Describe 関数を使用
>>> [child.name for child in arcpy.Describe('in_memory').children]
[u'test_tbl', u'test_fc', u'test_rd']
>>>
<\/code><\/pre>
<\/P>
インメモリワークスペース非対応は大きな問題というよりつまずき程度ですが、それでもつまずきです。ドキュメントには最初のパラメータが「トップレベルワークスペース」と書いてありながら、インメモリワークスペース非対応について言及されていません。ただ幸いなことにユーザーには少なくとも二つ以上インメモリデータソースをリストアップする方法があります。<\/P>
<\/P>
2017年6月更新:<\/STRONG><\/P>
<\/P>
このブログを書いてから約18ヶ月経ちました(「時間が飛ぶように過ぎる」と言いますが、本当にもう18ヶ月?)。ArcPy Walkとインメモリワークスペース問題について最初考えていたよりも複雑だとわかりました。説明します:<\/P>
>> arcpy.CreateFeatureclass_management('in_memory', 'test_fc')
>>> arcpy.CreateTable_management('in_memory', 'test_tbl')
>>> arcpy.CreateRasterDataset_management('in_memory','test_rd')
>>>
>>> # 一般的な "in_memory" ではなく "GPInMemoryWorkspace" を使って ArcPy Walk を使用
>>> next(arcpy.da.Walk('GPInMemoryWorkspace'))[2]
[u'test_tbl', u'test_fc', u'test_rd']
>>> <\/code><\/pre>
<\/P>
つまり、ArcPy Walkは実際にインメモリワークスペースだと認識すれば問題なく動作します。本当に苛立たしい点であり残念なのですが、この問題は単なる用語上の違いであり、Esriはいまだに修正できていません。機能的にはArcPy Walkは既にインメモリワークスペースで動作しています。ただ単に他のツールやユーザーがそれらを "in_memory" と呼ぶ一方で、この関数だけ "GPInMemoryWorkspace" と呼ばないと認識しないだけなのです。