Python スクリプトの共有方法
以下に、Python スクリプトを共有するときに使用できるいくつかの方法について説明します。
スクリプトの場所に基づいたデータ検索
スクリプトによっては、プログラマがハードワイヤード パスと呼ぶ、引数として渡されるものではない既存のデータへのパスが必要です。たとえば、出力パラメータのシンボル プロパティを既存のレイヤ ファイルに設定しなければならない場合や、データを既知のデータセットにクリップしなければならない場合があるかもしれません。
他者とツールを共有する場合は、スクリプトが必要なデータを見つけることができる状態を確保する必要があります。この方法として適切なものに、[ToolShare] フォルダ構造を使って、[ToolData] フォルダにプロジェクト データを配置し、スクリプトを [Scripts] フォルダに配置するというアプローチがあります。この方法を用いれば、確実にスクリプトの場所に基づいてデータを特定できます。
スクリプトを実行したときにスクリプトへのパスを特定する場合は、次の手順に従います。
scriptPath = sys.path[0]
この場所がわかれば、この場所に基づいてプロジェクト データを特定できます。これは、次のコード スニペットに示されています。
import arcpy import os import sys # Get the pathname to this script # scriptPath = sys.path[0] arcpy.AddMessage("Script folder: " + scriptPath) # Get the pathname to the ToolShare folder # toolSharePath = os.path.dirname(scriptPath) arcpy.AddMessage("ToolShare folder: " + toolSharePath) # Now construct pathname to the ToolData folder # toolDataPath = os.path.join(toolSharePath, "ToolData") arcpy.AddMessage("ToolData folder: " + toolDataPath) # Create the pathname to the parks feature class found in the ToolData folder # parkPath = os.path.join(toolDataPath, "Project.gdb/Parks") arcpy.AddMessage("Parks feature class: " + parkPath)
スクリプト コードを埋め込むと、sys.path[0] によってツールボックスの場所(コードの場所)が返されます。
テンポラリ ワークスペースの特定
スクリプト内にテンポラリ データを作成する場合は、テンポラリ データの作成とその後の削除のためのテンポラリ ワークスペースが必要です。
テンポラリ ワークスペースを選択するうえで注意すべきことをいくつか紹介します。
- ワークスペースへの書き込み権限が必要です。
- テンポラリ ワークスペース ジオプロセシング環境が設定されている場合は、これを使用します。この場合、ユーザが、すでに意図的に書き込み可能な場所を指定していることが想定されます。ArcGIS Server 上でジオプロセシング サービスを実行する場合は、ArcGIS Server がテンポラリ ワークスペースを特定の書き込み可能なフォルダに自動設定します。
- 現在のワークスペース環境をテンポラリ ワークスペースとして使用する場合は、リモート データベースに設定されている可能性があるため注意してください。テンポラリ ワークスペースにリモート データベースを使用することは、リモート データベースとの通信のオーバーヘッドがテンポラリ データの迅速な作成、書き込み、削除を妨げるため、避けてください。
- テンポラリ ワークスペース環境が設定されていない場合は、書き込み可能な場所を指定する必要があります。この場合には、いくつかのオプションがあります。
- [ToolShare] フォルダ構造を使用している場合は、[Scratch] フォルダの scratch.gdb を使用できます。防衛的プログラミングを採用している場合は、scratch.gdb が存在することを確認してください。ユーザによって削除されている可能性があります。
- スクリプト パラメータの 1 つが、フィーチャクラスのような出力データセットの場合は、出力データセットの場所への書き込み権限があると想定することができ、これをテンポラリ ワークスペースとして使用できます。ただし、この場所がフィーチャ データセットなのか、リモート データベースなのかを確認する必要があります(上述したように、リモート データベースをテンポラリ ワークスペースとして使用することは避けてください。リモート データベースとの通信のオーバーヘッドのために、テンポラリ データの迅速な作成、書き込み、削除が損なわれます)。
- どれもうまくいかない場合は、temp ディレクトリを使用できます。
- シェープファイルおよびパーソナル ジオデータベース ワークスペース内のフィーチャクラスには、2 GB というサイズの上限があります。2 GB は大きなデータ容量ですが、限度であることには変わりがありません。ファイル ジオデータベース ワークスペースには、デフォルトのデータセットの上限として 1 TB(1024 GB)が設定されています。テンポラリ データセットが 2 GB を上回ることが考えられる場合は、ファイル ジオデータベースをテンポラリ ワークペースとして使用します。
- CreateScratchName 機能を使用して、テンポラリ ワークスペースに一意なデータセット名を作成します。
次のコードの例には、非常に確実なテンポラリ ワークスペースの選択が示されています。このコードは、
- 現在のワークスペースをテンポラリ ワークスペースとして使用していませんが、現在のワークスペースを使用するよう簡単に変更できます。
- [ToolShare] フォルダ構造が使用されているものと想定しています。
- ファイル ジオデータベースの選択と使用を試み、シェープファイル ワークスペースを最後の手段として使用します。
import arcpy from arcpy import env import sys import os def getScratchWorkspace(outDataset): # outDataSet is assumed to be the full pathname to a dataset. Typically, # this would be a tool's output parameter value. # # Get the scratch workspace environment. If it's set, just return it. # scratchWS = env.scratchWorkspace if scratchWS: return scratchWS # Let's go fishing... # # If you're using the ToolShare folder structure, look for scratch.gdb in # the Scratch folder. # scriptPath = sys.path[0] toolSharePath = os.path.dirname(scriptPath) scratchWS = os.path.join(toolSharePath, "Scratch/scratch.gdb") if not arcpy.Exists(scratchWS): scratchWS = "" # No scratch workspace environment and no scratch.gdb in the ToolShare folder # if not scratchWS: # Get the workspace of the output dataset (if any passed in) # by going up one level # if outDataset: scratchWS = os.path.dirname(str(outDataset)) # If this isn't a workspace, go up another level and # test again. # desc = arcpy.Describe(scratchWS) if desc.dataType.upper() <> "WORKSPACE": scratchWS = os.path.dirname(scratchWS) desc = arcpy.Describe(scratchWS) if desc.dataType.upper() <> "WORKSPACE": scratchWS = "" # If we have a workspace, make sure it's not a remote (SDE) database. # If it is remote, set workspace to the system temp directory. # # If we don't have a workspace, just set it to the system temp directory. # usingTemp = False if scratchWS: desc = arcpy.Describe(scratchWS) if desc.workspaceType.upper() == "REMOTEDATABASE": scratchWS = arcpy.GetSystemEnvironment("TEMP") usingTemp = True else: scratchWS = arcpy.GetSystemEnvironment("TEMP") usingTemp = True # If we're using the system temp directory (a shapefile workspace), look # for a scratch file geodatabase. If it exists, use it. If it doesn't, # create it. # if usingTemp: scratchWS = os.path.join(scratchWS, "scratch.gdb") if arcpy.Exists(scratchWS): return scratchWS else: arcpy.CreateFileGDB_management(arcpy.GetSystemEnvironment("TEMP"), "scratch.gdb") return scratchWS # Main demonstration routine # One optional input parameter, a feature class. # aDatasetpath = arcpy.GetParameterAsText(0) scratch = getScratchWorkspace(aDatasetpath) arcpy.AddMessage("Scratch workspace: " + scratch) # Create a scratch feature class in the scratch workspace # scrname = arcpy.CreateScratchName("temp", "","featureclass", scratch) arcpy.AddMessage("Scratch feature class is: " + scrname) arcpy.CreateFeatureclass_management(scratch, os.path.basename(scrname), "point") arcpy.AddMessage(arcpy.GetMessages())
Python モジュールの共有
他の最近のプログラミング言語と同様に、Python でも、他の Python スクリプトにあるルーチンを呼び出すことができます。Python コードを開発すればするほど、スクリプト間での共有のための Python ルーチンの開発が望まれるでしょう。このセクションでは、ルーチンの共有方法を簡単に説明し、公式の Python Web サイト(http://www.python.org)をはじめとした、ルーチンの共有を効果的に調査および実装できるようにする十分な情報をご紹介します。
スクリプト helloworld.py の内容は次のようになっています。
def dosomething(): print "Hello world" def somethingelse(): print "Goodbye world"
スクリプト main.py の内容は次のようになっています。
import sys, os, helloworld helloworld.dosomething() helloworld.somethingelse()
スクリプト main.py は、helloworld モジュール(モジュール名はスクリプト名から「.py」拡張子を除外したものです)を、sys および os モジュールとともにインポートします。helloworld の拡張子「.py」は必要ありません(実際、この使用は認められません)。
スクリプト helloworld.py は、あちこちで目にする「Hello world」を印刷する dosomething と、これよりも目にする頻度の低い「Goodbye world」を印刷する somethingelse と呼ばれる 2 つのルーチンを(def ステートメントで)実装します。main.py が実行されると、「Hello world」と「Goodbye world」を印刷するこれらの 2 つのルーチンが呼び出されます。
上記のこれら 2 つのモジュールには、arcpy のインポート、ジオプロセシング環境の取得、エラー対応など、多数の項目が入っていません。これらのトピックについては、「Python の概要」をご参照ください。
Python によるモジュールの検索先
main.py が実行されると、インポート ディレクティブは、システム ディレクトリ パスのリストにある helloworld.py という名前のファイルを Python に検索させます。Python が最初に検索する場所は、インポートディレクティブを格納したスクリプトと同じディレクトリである現在のディレクトリ(この場合はmain.py)です。これらのパスは PythonWin の対話形式のウィンドウに一覧表示できます。
import sys sys.path
次のように、インポート ディレクティブにパスを入力することはできません。
import E:\SharedScripts\helloworld
そうではなく、Python によるモジュールの検索先となるディレクトリのリストを変更する必要があります。このディレクトリのリストには、ArcGIS によってインストールされる PYTHONPATH と呼ばれる Windows の環境設定が格納されています。この設定を変更するには、次の手順を実行します。
- Windows の[スタート] メニューで、[設定] → [コントロール パネル] の順にクリックします。
- [System] ファイルを見つけて、開きます。
- [詳細設定] タブをクリックし、[環境変数] をクリックします。
- [システム環境変数] の下で PYTHONPATH 変数にスクロールし、これをクリックして選択します。
- PYTHONPATH 変数がない場合は、[新規作成] をクリックします。[変数名] テキスト ボックスに「PYTHONPATH」と入力します。
- [変数値] テキスト ボックスに、「<ArcGIS install directory>\bin;<ArcGIS install directory\arcpy(例として、C:\Program Files\ArcGIS\Desktop10.0\bin;C:\Program Files\ArcGIS\Desktop10.0\arcpy)」と入力します。
- [OK] をクリックします。
- PYTHONPATH 変数が存在する場合は、[編集] をクリックします。
PYTHONPATH の内容に、最初のエントリとして <ArcGIS install directory>\bin;<ArcGIS install directory\arcpy が含まれているはずです。arcgisscripting モジュールはここにあります。これ以外にも Python モジュールを格納したディレクトリへのパスを追加することができます。パスはセミコロンで区切り、セミコロンの前後にはスペースを入れないでください。
パスはコード内に追加することもできます。
sys.path.append("e:\sharedmodules")
Python モジュールの共有
他のユーザにスクリプト ツールを配布する場合で、そのスクリプトが他のモジュールをインポートする場合には、2 つのオプションがあります。
- すべてのスクリプトを同一ディレクトリに格納します。
- ユーザには、追加的なモジュールをユーザのシステムの任意の場所にインストールして、PYTHONPATH 変数を変更するよう指示します。
ユーザによる Python コードの変更が必要となるため、sys.path.append() の使用はお勧めしません。
パスとエスケープ文字
Python のように、UNIX と C プログラミング言語に根ざしたプログラミング言語では、円記号(バックスラッシュ)[\]がエスケープ文字として扱われます。たとえば \n は、テキスト出力を書き出す時にキャリッジ リターンを挿入する場合に使用され、\t はタブ記号を挿入する場合に使用されます。スクリプトのパスで円記号が区切り記号として使用されている場合、Python はこれをスキャンして、\n があればこれをキャリッジ リターンに、\t があればこれをタブに置き換えます(エスケープ文字の組み合わせは \n と \t だけではありません)。
この問題を避ける最も簡単な方法は、以下に示す r ディレクティブを使用してパスを未加工の Python 文字列に変換することです。これにより、Python に円記号を無視するよう指示することができます。
thePath = r"E:\data\teluride\newdata.gdb\slopes"
ライセンスの確認
エクステンションを使用しているか、ArcView や ArcEditor 製品レベルでは利用できないツールに依拠しているスクリプトの場合は、まずライセンスと製品レベルを確認する必要があります。