共享 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 服务器上运行的地理处理服务,ArcGIS Server 会自动将临时工作空间设置为可写入的特定文件夹。
- 在将当前工作空间环境用作临时工作空间时要慎重,当前环境可能是一个远程数据库,而您从不希望使用远程数据库作为临时位置,因为与远程数据库进行通信的开销非常大,会导致您无法快速创建、写入和删除临时数据。
- 如果尚未设置临时工作空间,则需要查找一个可写入的位置。在这种情况下,可选择以下几种方法:
- 如果使用的是 ToolShare 文件夹结构,则您可使用 Scratch 文件夹中的 scratch.gdb。如果您采用的是防错性编程,则应检查 scratch.gdb 是否存在,因为用户可能已将其删除。
- 如果某个脚本参数为输出数据集(如要素类),则可确定您对输出数据集的位置具有写入权限,并可将其用作临时工作空间。但您需要检查该位置是要素数据集还是远程数据库。(如上所述,您从不希望将远程数据库用作临时位置,因为与远程数据库进行通信的开销非常大,会导致您无法快速创建、写入和删除临时数据。)
- 当其他所有方法均失败时,您始终可以使用系统的 temp 目录。
- shapefile 和个人地理数据库工作空间中的要素类大小不得超过 2 GB。虽然 2 GB 能够容纳许多数据,但这仍是一个限制因素。文件地理数据库工作空间对于数据集的默认限制为一兆兆字节 (1024 GB)。如果您认为临时数据集的大小可能会超过 2 GB,则请使用文件地理数据库作为临时工作空间。
- 使用 CreateScratchName 函数在临时工作空间中创建唯一数据集名称。
以下代码示例显示了查找临时工作空间的代码执行,该程序极具防错性。该代码
- 不使用当前工作空间作为临时工作空间,如要使用,也很容易进行修改
- 假定您使用 ToolShare 文件夹结构
- 尝试查找和使用文件地理数据库,并且除非必需,否则不使用 shapefile 工作空间
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 网站 (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 脚本实施两个称为 dosomething 的例程(使用 def 语句),dosomething 打印出现较频繁的“Hello world”,而 somethingelse 打印较少出现的“Goodbye world”。当执行 main.py 时,main.py 会调用这两个例程来打印“Hello world”与“Goodbye world”。
以上所示的两个模块缺少许多内容,如导入 arcpy、获取地理处理环境、错误处理等类似内容。在 Python 快速浏览中涵盖了所有这些主题。
Python 查找模块的位置
当执行 main.py 时,import 指令会使 Python 在它的系统目录路径列表中查找名为 helloworld.py 的文件。Python 会首先在当前目录中查找,即包含 import 指令的脚本的目录(在本例中为 main.py)。您可以使用以下代码在交互式 PythonWin 窗口中显示这些路径的列表:
import sys sys.path
您不能在 import 指令中输入路径,如
import E:\SharedScripts\helloworld
而是必须更改 Python 查找模块的目录的列表。此目录列表包含在名为 PYTHONPATH 的 Windows 环境设置中,由 ArcGIS 安装。要更改此设置,请执行以下操作:
- 在 Windows“开始”菜单下,单击设置 > 控制面板。
- 找到“系统”文件并将其打开。
- 单击高级选项卡,然后单击环境变量。
- 在系统变量下,滚动至 PYTHONPATH 变量,然后单击将其选中。
- 如果不存在 PYTHONPATH 变量,则单击新建。在变量名称:文本框中,输入 PYTHONPATH。
- 在变量值:文本框中,输入 <ArcGIS 安装目录>\bin;<ArcGIS 安装目录\arcpy(例如 C:\Program Files\ArcGIS\Desktop10.0\bin;C:\Program Files\ArcGIS\Desktop10.0\arcpy)。
- 单击确定。
- 如果存在 PYTHONPATH 变量,则单击编辑。
PYTHONPATH 内容中的第一个条目应该是 <ArcGIS 安装目录>\bin;<ArcGIS 安装目录\arcpy。这是 arcgisscripting 模块所在的位置。您可以追加更多指向包含 Python 模块的目录的路径。这些路径以分号隔开且分号左右不能有任何空格。
您还可以通过以下方式在代码中追加路径
sys.path.append("e:\sharedmodules")
共享 Python 模块
如果要将脚本工具提供给其他用户,并且该脚本需要导入其他模块,您可以选择以下两种方法:
- 将所有脚本放于同一目录中。
- 通知用户在其系统中的某个位置安装其他模块并修改 PYTHONPATH 变量。
不建议使用 sys.path.append(),因为它要求用户更改 Python 代码。
路径和转义字符
基于 UNIX 的编程语言以及 C 编程语言与 Python 类似,都将反斜线 (\) 视为转义字符。例如,\n 用于在写入文本输出时插入一个回车符,而 \t 用于插入制表符。如果脚本中的路径使用反斜线作为分隔符,则 Python 会搜索此分隔符,并在遇到 \n 和 \t 时,分别将其替换为回车符和制表符。(除了 \n 和 \t 外,还有其他的转义字符序列。)
防止此类状况的最简单方法是使用 r 指令将路径转换为 Python 原始字符串,如下所示。这会指示 Python 忽略反斜线。
thePath = r"E:\data\teluride\newdata.gdb\slopes"