
简介《[初学入门]ArcGIS中Python脚本的使用》是一份面向GIS初学者与ArcGIS入门用户的单篇DOCX教程旨在用较低门槛梳理Python脚本在地理处理自动化中的基础用法。压缩包仅含1个DOCX文件大小约490KB轻量便于随时查阅。内容从Python数学运算、字符串、模块导入、def函数、if/while/for流程控制与输入输出讲起再过渡到arcpy地理处理对象、帮助查询、列表参数、工具箱与别名、ModelBuilder内嵌脚本、PythonWin调试以及Describe/Exists和地图代数等实用环节形成从语言基础到ArcGIS集成的学习路径。已有1492人学习适合希望补齐脚本基础、理解地理处理编程模型并用于课程练习或日常空间数据处理的上手者。1. 从一台装了两套 Python 的机器说起ArcGIS 脚本为啥总在版本上栽跟头接手一个流域分析的工作目录三十多个 shapefile 要重投影、裁到同一个研究区再逐个算坡度。手工在工具箱里点一个文件四步点完一百多次中间还得记住哪几个已经做过。这种活儿干过一遍就明白ArcGIS 中 Python 脚本不是“进阶技能”是止损手段——把一百多次点击压成二十行代码跑一遍去接杯水回来收结果。这份 34 页的讲义走的就是这条路前半部分打 Python 语法底子后半部分全部押在地理处理对象上从创建 geoprocessor、抓 List 和 Describe一路讲到 ModelBuilder 里挂脚本、用游标批量改属性表。它适合刚摸到 ArcGIS 桌面端、鼠标点得溜但没写过脚本的人也适合写过几句 arcpy、却总在路径、别名和解释器版本上翻车的人。2. 环境与骨架地理处理对象的两种创建方式与第一个能跑通的脚本2.1 先把 Python 版本这件事钉死装 ArcGIS 桌面端的时候安装程序会顺手带一个 Python 解释器进去9.x 时代是 2.510.x 是 2.6 或 2.7位置通常在C:\Python27\ArcGIS10.x\python.exe。问题在于很多人机器上还躺着另一个独立安装的 PythonPATH 顺序一变命令行敲python起来的是谁就说不准了。脚本里一句import arcgisscripting报 ImportError八成不是代码写错是解释器选错了。开工前先让脚本自报家门# 先确认自己跑在哪个解释器上这是排查一切 ImportError 的第一步 import sys print(sys.version) # 例如 2.7.8 (default, Jun 30 2014, 16:03:49) [MSC v.1500 32 bit (Intel)] print(sys.executable) # 例如 C:\Python27\ArcGIS10.3\python.exesys.version告诉你版本号和位数sys.executable告诉你实际被调用的可执行文件路径。两行输出对不上预期后面所有调试都是白费。我一般会在每个脚本开头留这两行做注释状态跑通之后再删掉。提示不要尝试把随 ArcGIS 安装的 Python 升级到新版本。地理处理模块是针对特定解释器版本编译的二进制扩展换了版本号模块加载直接失败而且回滚很麻烦。除了版本还要确认扩展模块能不能加载。下面这段是判断环境是否可用的最小验证try: import arcgisscripting gp arcgisscripting.create(9.3) print(geoprocessor ok) except ImportError: print(wrong interpreter: arcgisscripting not available)create()的参数是目标版本号它决定了这个对象背后能挂载哪一套工具集。9.3 和 10.0 的工具签名有差异写错版本号不会立刻报错而是在调用某个工具时才炸排查成本很高。2.2 两种 geoprocessor 写法区别不只是风格同一个地理处理对象讲义里给了两条创建路径这两条路在当年是实打实的取舍# 写法一arcgisscripting官方入口只能配 ArcGIS 自带的解释器 import arcgisscripting gp arcgisscripting.create(9.3) # 参数是目标版本号 gp.workspace c:/gisdata/proj # 相对路径的基准目录 gp.overwriteoutput 1 # 1 表示允许覆盖同名输出 gp.clip_analysis(standb4, clipcov, standb4_clip, POLY, 1.25)# 写法二走 COM任何装了 pywin32 的解释器都能调起来 import win32com.client gp win32com.client.Dispatch(esriGeoprocessing.GpDispatch.1) gp.workspace c:/gisdata/proj gp.clip_analysis(standb4, clipcov, standb4_clip, POLY, 1.25)第一种是编译进 Python 的扩展模块性能好、异常信息清晰代价是绑死解释器版本。第二种通过 COM 注册表拿到对象好处是理论上可以跨 Python 版本运行坏处是每次调用都有跨进程开销出错时抛出来的是 COM 错误码翻译成人话要花点功夫。真正要写批处理、跑几千个要素的时候性能差距是能感觉到的我一般优先用 arcgisscripting只有在维护别人留下的老脚本时才碰 Dispatch。clip_analysis这五个参数依次是输入要素、裁剪要素、输出要素、聚类容差类型、XY 容差。容差那两个参数在数据本身干净的时候可以省略但如果输入是从别的坐标系转过来的留着反而更容易出问题宁可显式写上。到了 10.x官方把这一层封装成了arcpy不再需要手动 createimport arcpy arcpy.env.workspace rC:\gisdata\proj arcpy.env.overwriteOutput True arcpy.Clip_analysis(standb4.shp, clipcov.shp, standb4_clip.shp)对象模型没变只是把gp.xxx_yyy换成了arcpy.Xxx_yyy。看懂 9.x 的写法10.x 的脚本基本能直接读反过来也一样。2.3 workspace、覆盖开关与一个完整的三步流水线讲义的第一个完整例子是三步串联coverage 转 shapefile、做缓冲区、再裁剪。这三步覆盖了脚本化最典型的三个动作——格式转换、几何运算、按空间范围筛选。import arcgisscripting gp arcgisscripting.create(9.3) gp.workspace c:/gisdata/hmbarea # 之后所有相对路径都相对这里 gp.overwriteoutput 1 # 不加这句第二次运行必然报输出已存在 # 第一步把 coverage 里的弧段导出成 shapefile gp.copyfeatures_management(streams/arc, streams.shp) # 第二步对河网做 200 单位缓冲 gp.buffer_analysis(streams.shp, stbuff200.shp, 200) # 第三步用缓冲结果裁剪地质图 gp.clip_analysis(geol.shp, stbuff200.shp, geolstr200.shp) print(gp.GetMessages())copyfeatures_management里的management是 Data Management 工具箱的别名这个后缀不能省原因在 4.1 会详细说。buffer_analysis的第三个参数是距离写成纯数字200时单位跟着输出坐标系走——如果坐标系是地理坐标200 就是 200 度结果会离谱到让你怀疑人生。稳妥的写法是带上单位200 Meters。gp.GetMessages()是我强烈建议每段脚本结尾都加的一句。地理处理工具执行成功不代表结果正确工具内部经常会产生警告例如要素被简化、部分记录被跳过这些信息只从消息队列里出来不看就等于把黑匣子盖上。workspace这个属性值得单独说一句。它影响的不只是输入路径的相对基准还影响 List 系列方法的扫描范围、地图代数表达式里栅格名的解析。很多人写完脚本在东家机器上跑得好好的换台机器就找不到数据往往是 workspace 里混用了正反斜杠或者漏了末尾的分隔符。统一用正斜杠或者统一加r前缀能省掉大量血泪经验。3. 语法落地运算符、字符串切片和流程控制在 GIS 数据里的真实用法3.1 整型、浮点型与取模坡度算错三倍的根源Python 的除法行为是这套语法里最容易咬人的地方。在 2.x 里两个整型相除结果还是整型print(5 / 2) # 2不是 2.5 print(5.0 / 2) # 2.5只要有一个是浮点结果就是浮点 print(5 % 2) # 1取模 print(2 ** 3) # 8幂运算这条规则放到 GIS 里就是灾难。高程差除以水平距离算坡度两个都是整型结果被截断成 0 或 1整个栅格图全废。讲义里给的对策很简单——参与运算的任意一个数写成浮点形式或者显式float()转换。取模在方位角计算里非常顺手。方位角加 180 度要逆转方向加完可能超过 360取个模就自动回卷az 270 newaz az 180 print(newaz % 360) # 902 ** 0.5是开平方的土办法因为不 import math 就没有sqrt()。这行在讲义里被特意点出来属于没模块时的应急手段正式脚本里还是老老实实import math用math.sqrt()可读性差太多了。同一套思路被用来判断 DEM 的高程单位这个例子我觉得是整份讲义里最实用的一段import fileinput infile rc:/gisdata/dem/woodside.dem firstline fileinput.input(infile)[0] # 取第一行 unitchar firstline[539] # 第 540 个字符下标从 0 起 unit (unknown: not a 7.5 DEM?) if unitchar 1: unit feet if unitchar 2: unit meters print(\nElevation in unit) fileinput.close()USGS 7.5 分幅 DEM 是纯文本格式头部把高程单位编码在固定位置的单个字符上1是英尺2是米。这个信息拿不到后面算坡度、算体积、算填挖方全是错的——英尺和米差 3.28 倍而且不会报错只会安静地给你一个错误的数字。脚本里先探单位再决定要不要乘 0.3048这一步不能省。3.2 字符串切片与 r 前缀路径处理的半壁江山GIS 脚本里字符串用得最多的地方就是路径而路径处理出问题九成是转义字符惹的祸p2 d:\\work\\soil.shp # 双反斜杠转义后才是单个反斜杠 print(p2) # d:\work\soil.shp p3 rd:\work\soil.shp # r 前缀反斜杠就是反斜杠本身 print(p3) # d:\work\soil.shpr前缀对 Windows 路径来说是刚需因为\n、\t、\f在普通字符串里都有特殊含义一个d:\temp\new会被解释成带着换行和制表符的怪物。凡是硬编码路径我习惯性全部加r。切片和字符串方法是另一组高频操作。下标从 0 开始s[1:3]取的是下标 1 到 2不含 3这个左闭右开规则跟 Python 的 range 一致s gisdata print(s.capitalize()) # Gisdata print(s[0]) # g print(s[-2:]) # ta从倒数第二个取到末尾 print(s[2:4]) # sd print(s * 2) # gisdatagisdata print(s.isupper()) # Falsesplit()把路径拆成列表find()返回下标endswith()做后缀判断这三个组合起来能干很多事p d:/work/lu.shp print(p.find(.)) # 10最后一个点的位置 plist p.split(/) # [d:, work, lu.shp] print(plist[-1]) # lu.shp文件名 print(p.endswith(.shp)) # True有个细节值得留意find(.)在含小数点的路径里会返回第一个点的位置不是扩展名那个点。要拿扩展名用p[p.rfind(.)1:]或者干脆os.path.splitext()别图省事。3.3 用 def 把重复步骤压成函数用 if/for 把逻辑串起来函数是脚本从“能跑”到“能维护”的分水岭。讲义给的例子是度与弧度的互转因为math里的三角函数全部吃弧度import math def radians(angdeg): 度转弧度 return angdeg * math.pi / 180.0 def degrees(angrad): 弧度转度 return angrad * 180.0 / math.pi print(math.sin(radians(45))) # 0.707106781187 print(degrees(math.acos(0.5))) # 60.0注意分母写成180.0而不是180这就是 3.1 那条规则的直接应用。函数定义好之后可以像变量一样传参、赋值后面在太阳高度角计算里反复调用代码短了一截。流程控制的三种结构在讲义里是用同一个业务场景串起来的——批量生成山影栅格。山影工具要两个参数太阳高度角和方位角而这两个值随季节和纬度变化lat 30 # 研究区纬度南半球为负 decl 20 # 太阳倾角夏至 23.44春秋分 0冬至 -23.44 sunangle 90 - lat decl azimuth 180 # 正午正南方向 if sunangle 90: sunangle 180 - sunangle # 超过 90 度要折回来 azimuth 0 # 太阳从北边照过来 print(sunangle, azimuth)if、while、for三个结构的共同点是冒号结尾加缩进这个规则在编辑器的自动缩进里体现得最明显——冒号一打下一行自动往里退一格要跳出代码块就按退格。只需要执行一条语句时可以把它写在冒号同一行但我不建议这么干后面加第二行时容易漏缩进。while适合不知道要循环多少次、只知道退出的条件的场景x 1 while x 10: print(x) x x 1 # 忘写这句就是死循环for适合遍历确定的集合。下面这段遍历目录、筛出 shapefile几乎是所有批处理脚本的骨架import os ws c:/gisdata/hmbarea ilist os.listdir(ws) # 目录下所有文件名 fcs [] # 空列表装筛出来的结果 for i in ilist: if i.endswith(.shp): fcs.append(i) for fc in fcs: print(fc)os.path.exists()的三分支判断是另一个高频片段用来区分“文件在”“目录在但文件不在”“啥都没有”三种情况import os.path if os.path.exists(d:/testfolder/test.txt): print(txt exists) elif os.path.exists(d:/testfolder): print(folder only, txt missing) else: print(neither)这段逻辑在 4.3 会升级成一个带 describe 的体检函数用在批量处理前的预检查里。先判断再处理比让工具抛异常再捕获要干净得多尤其是处理几百个文件的时候一个坏文件不该让整批任务停摆。3.4 sys.argv把硬编码参数变成运行时输入前面所有例子的参数都是写死的这在调试阶段没问题交付给别人就不行了。讲义给的第一个方案是sys.argvimport sys lat float(sys.argv[1]) # 下标从 1 开始0 是脚本自身路径 decl float(sys.argv[2]) sunangle 90 - lat decl azimuth 180 if sunangle 90: sunangle 180 - sunangle azimuth 0 print(sun angle str(sunangle)) print(azimuth str(azimuth))在 PythonWin 里点运行弹出的 Arguments 一栏填40 23.44两个值就分别进了argv[1]和argv[2]。这一步的意义在于脚本第一次有了“调用接口”而不是每次都去改源码。两个细节argv里拿到的永远是字符串参与数学运算必须显式float()转换输出时数字和字符串拼接也要str()a 1在 Python 2 里直接报 TypeError。sys.argv只适合命令行和 PythonWin 里手跑。要把脚本挂成工具箱工具得换成gp.GetParameterAsText()这个差别在第 6 章展开它也是从“写脚本的人”变成“做工具的人”的分界线。4. 工具调用别名机制、List/Describe 遍历与游标批量改属性4.1 同名工具怎么区分别名不是可选装饰工具箱里的工具名会重复。Clip在 Coverage 工具集里有一个在 Data Management 的栅格工具集里还有一个两者接受的输入类型完全不同。图形界面里你点哪个就是哪个脚本里只有一个字符串怎么区分答案是别名——它已经是工具全名的一部分了。别名对应工具箱conversionConversion Tools3d3D Analyst ToolsanalysisAnalysis ToolsmanagementData Management ToolscartographyCartography ToolssaSpatial Analyst ToolsstatsSpatial Statistics ToolsarcCoverage ToolsgaGeostatistical Analyst ToolslrLinear Referencing ToolsgeocodingGeocoding Tools在 ArcToolbox 里右键某个工具看属性就能查到它的别名。写进脚本就是工具名_别名import arcgisscripting gp arcgisscripting.create(9.3) gp.workspace c:/gisdata/hmbarea gp.overwriteoutput 1 # management 别名要素类到 shapefile 的格式转换 gp.copyfeatures_management(streams/arc, streams.shp) # analysis 别名矢量缓冲 gp.buffer_analysis(streams.shp, stbuff200.shp, 200 Meters) # analysis 别名矢量裁剪 gp.Clip_analysis(geol.shp, stbuff200.shp, geolstr200.shp)三个参数一个都不能省省掉别名会报“工具不存在”而不是自动帮你挑一个这点跟很多人想的不一样。如果一段脚本连续调用同一个工具箱里的多个工具可以设gp.Toolbox属性省掉后缀gp.Toolbox Analysis gp.Buffer(streams.shp, stbuff200.shp, 200 Meters) gp.Clip(geol.shp, stbuff200.shp, geolstr200.shp)但这里有个坑Toolbox是全局状态切到另一个工具箱之后不切回来后面所有不带别名的调用都会用错工具集。我一般只在短脚本里用这种简写长脚本一律写全名多敲几个字符换来的确定性很值。4.2 List 系列配 Describe先摸清数据长什么样再动手地理处理脚本有一半时间花在“确认输入是什么”上。List 系列方法负责枚举Describe 负责取元数据两者配合就是脚本的眼睛。List 家族成员不少ListFeatureClasses、ListRasters、ListDatasets、ListTables、ListWorkspaces、ListFields、ListIndexes。选哪个取决于数据的组织形态——shapefile 是要素类geodatabase 里可能同时有要素类和栅格coverage 是一个目录下的多个数据集。讲义特意点明了一条遍历 coverage 要用ListDatasets而不是ListFeatureClasses因为 coverage 在文件系统层面不是单个文件要素类那一套枚举逻辑套不上去。import arcgisscripting gp arcgisscripting.create(9.3) gp.workspace c:/gisdata/hmbarea # 第一个参数是通配符第二个是要素类型过滤 fcs gp.ListFeatureClasses(w*, polygon) for fc in fcs: print(fc)ListFeatureClasses的签名是{wildCard}, {FeatureType}两个都可选。不传通配符就返回工作空间下全部要素类传w*只返回 w 开头的第二个参数限定几何类型为 polygon。拿到数据集之后用 Describe 读元数据。下面这段列出土地利用栅格的字段清单import arcgisscripting gp arcgisscripting.create(9.3) gp.workspace c:/gisdata/hmbarea fieldList gp.ListFields(landuse, *, all) dsc gp.describe(landuse) print(landuse dsc.DataType :) for field in fieldList: print(field.Name, field.Type)ListFields三个参数分别是数据集、通配符、字段类型all表示全要。返回的是 Field 对象列表每个对象有Name、Type、Length、Precision、Scale等属性。dsc.DataType会返回RasterDataset、Shapefile、FeatureClass这类字符串用来分支处理特别方便。这里有个容易翻车的点List 返回的是迭代器遍历一次就空了。想反复用先list()或者for存进普通列表fcs list(gp.ListFeatureClasses()) print(len(fcs)) # 第一次正常 for fc in fcs: print(fc) # 第二次遍历依然有效Describe对象上的属性名跟具体数据类型相关。要素类有ShapeType、SpatialReference栅格有MeanCellHeight、Formatshapefile 有ShapeTypecoverage 有FeatureClassType。属性不存在时返回 None 而不是报错所以判空要比判存在更靠谱。4.3 循环里做体检exists 加 describe 的组合用法批量处理最怕的是中途遇到一个坏文件。第一种做法是让工具抛异常整批停下来第二种做法是提前探一遍把坏数据跳过并记日志。我倾向第二种尤其是数据来源不受控的时候。import arcgisscripting import os gp arcgisscripting.create(9.3) ws c:/gisdata/hmbarea gp.workspace ws for name in os.listdir(ws): if not name.endswith(.shp): continue # 不是 shapefile跳过 full os.path.join(ws, name) if not gp.exists(full): print(missing: full) # 路径写错了或者文件被移走 continue d gp.describe(full) if d.ShapeType.lower() polygon: # 只处理面要素其他几何类型直接略过 print(name d.ShapeType d.SpatialReference.Name)os.listdir()和gp.exists()的分工是前者只管目录里有什么后者才判断这个完整路径在 ArcGIS 眼里是不是合法数据源。两者都过一遍才算真正“可用”。d.ShapeType返回的是Polygon、Polyline、Point这类首字母大写的字符串比较前统一lower()能避免大小写不一致带来的漏判。d.SpatialReference.Name是我最常用的一个属性批量处理前先把所有数据集的坐标系打印一遍能立刻发现混进来的“未定义坐标系”文件。这类文件参与投影和裁剪时不会报错只会安静地按默认参数处理结果偏到哪都不知道。4.4 地图代数把栅格计算写进脚本栅格运算是另一套调用方式叫地图代数Map Algebra。它不走普通的工具调用接口而是把表达式交给 Spatial Analyst 扩展去解析import arcgisscripting gp arcgisscripting.create(9.3) gp.CheckOutExtension(Spatial) # 必须先签出扩展模块 gp.workspace c:/gisdata/dem # 表达式里的栅格名相对于 workspace 解析 out gp.SingleOutputMapAlgebra_sa(dem * 0.3048) out.save(c:/gisdata/dem/dem_m)几个关键点CheckOutExtension(Spatial)是必须的前置动作不签出直接调地图代数会报许可错误表达式里的栅格名是相对 workspace 的完整路径要加引号包一层SingleOutputMapAlgebra_sa返回的是一个栅格对象必须.save()才会真正落盘不 save 就等于算了个寂寞。_sa后缀就是 Spatial Analyst 的别名跟 4.1 讲的规则一致。表达式本身支持 - * /、比较运算、逻辑运算和常见的栅格函数写起来比一个个调工具快得多。10.x 之后改成这样形式上更接近普通 Pythonimport arcpy from arcpy.sa import * arcpy.CheckOutExtension(Spatial) arcpy.env.workspace rC:\gisdata\dem out Raster(dem) * 0.3048 out.save(rC:\gisdata\dem\dem_m)运算符重载了Raster(dem) * 0.3048直接就是栅格乘法可读性好了很多但底层还是同一套地图代数引擎。4.5 游标批量改属性表的正确姿势矢量数据改属性工具对话框里能做的很有限游标Cursor才是主力。三种游标分工明确SearchCursor 只读UpdateCursor 读写InsertCursor 只写。下面这个例子把空值的 CODE 字段填成 0import arcgisscripting gp arcgisscripting.create(9.3) gp.workspace c:/gisdata/hmbarea rows gp.UpdateCursor(landuse.shp) row rows.Next() while row: if row.getValue(CODE) is None: row.setValue(CODE, 0) rows.UpdateRow(row) # 不调这句修改不会生效 row rows.Next() del rows # 必须释放否则数据集被锁住UpdateCursor拿到的是行对象的遍历器Next()推进getValue/setValue读写字段UpdateRow提交单行修改。最容易忘的是最后那句del rows——游标不释放文件锁会一直挂着后面任何工具想写这个数据集都会报锁冲突。这个坑我在第一次写批量脚本的时候踩了整整一下午日志里只有一句语焉不详的“无法获取锁”。10.x 提供了da版本用with语句自动管理资源字段名用列表传速度快不少import arcpy with arcpy.da.UpdateCursor(landuse.shp, [CODE]) as cur: for row in cur: if row[0] is None: row[0] 0 cur.updateRow(row)with块结束自动释放游标不用再手动del。字段访问从row.getValue(CODE)变成row[0]索引和字段列表的顺序对应写错下标不会报错但会改错字段这个要小心。5. 避坑与排查脚本在 ArcGIS 里跑不通的五个高发点5.1 环境与调试入口现象脚本在 PythonWin 里点运行窗口闪一下就没了或者报ImportError: No module named arcgisscripting。原因python.exe选错了。机器上有多个解释器IDE 记住的是上一次用过的那个而地理处理模块只装在 ArcGIS 自带的解释器下。解决在 PythonWin 的 Tools → Options 里确认解释器路径指向C:\Python27\ArcGIS10.x\python.exe命令行调试时用绝对路径调用不要依赖 PATH。加一句print(sys.executable)把实际路径打出来比猜快得多。注意调试地理处理脚本时优先用 PythonWin它对 COM 和地理处理对象的支持最完整断点、变量观察、交互窗口都能用。用别的编辑器跑出莫名其妙的错误先换回 PythonWin 复现一次再判断。现象脚本里写了中文注释运行报SyntaxError: Non-ASCII character。原因Python 2 默认按 ASCII 解析源码遇到中文字节就崩。解决文件头加# -*- coding: utf-8 -*-声明编码更稳的做法是干脆不写中文注释输出信息也统一用英文。这份讲义在正文里明确提醒了这一点——注释里的中文会直接影响执行结果不是显示问题。5.2 数据与路径现象工具报ERROR 000732: 数据集 不存在或不受支持但路径在资源管理器里明明能看到。原因三种可能——反斜杠被转义吃掉了、workspace 和相对路径拼错了、扩展名被隐藏导致实际文件名和写的名字不一致。解决路径统一加r前缀或改用正斜杠调工具前先gp.exists(完整路径)探一下把os.listdir()的结果打印出来跟预期比对。这三步走完99% 的路径问题都能定位。现象Clip跑完输出要素的属性表是空的或者只剩几个字段。原因调到了 Coverage 工具箱下那个同名工具。它和 Analysis 下的 Clip 名字一样、参数位置一样但处理逻辑和输出格式完全不同。解决显式写别名gp.Clip_analysis(...)永远不要用不带后缀的裸工具名。同一个项目里如果有两处裁剪务必确认两处用的是同一个别名的工具。5.3 参数与输出现象buffer距离写200结果缓冲区大得离谱或者小得看不见。原因距离单位跟着输出坐标系走。坐标系是地理坐标度时200 被解释成 200 度。解决先投影到米制坐标系再做缓冲或者显式写200 Meters。同理Select_analysis的表达式里数值比较也要注意单位。现象第二次运行脚本报“输出已存在”或者中途失败后重跑一直报锁冲突。原因overwriteoutput没开或者上一次的游标没释放文件锁还挂着。解决脚本开头统一设gp.overwriteoutput 1游标用完立刻del10.x 用with实在释放不掉关掉 PythonWin 的所有解释器进程再重试。我现在的习惯是每个写数据的脚本都在 finally 块里做清理宁可多写几行。6. 二次开发把脚本挂成工具、塞进模型的三步改造脚本能跑通只是第一步真正让别人也能用得把它挂成工具箱里的工具。这里有个关键改动sys.argv在工具箱环境里拿不到值必须换成GetParameterAsText()。import arcgisscripting gp arcgisscripting.create(9.3) # 下标从 0 开始顺序必须和工具对话框里的参数顺序严格一致 in_fc gp.GetParameterAsText(0) clip_fc gp.GetParameterAsText(1) out_fc gp.GetParameterAsText(2) buf_dist gp.GetParameterAsText(3) gp.workspace rC:\gisdata\proj gp.Buffer_analysis(in_fc, tmp_buf.shp, buf_dist) gp.Clip_analysis(clip_fc, tmp_buf.shp, out_fc) gp.AddMessage(output: out_fc) # 消息会显示在工具执行结果窗口两种取值方式的差异值得记牢取值方式生效环境索引起点类型sys.argvPythonWin / 命令行10 是脚本自身字符串gp.GetParameterAsText工具箱工具 / ModelBuilder0字符串改造分三步走。第一步把源码里写死的路径全部替换成GetParameterAsText(n)下标顺序和后面要配的参数表一一对应。第二步在 ArcToolbox 里新建脚本工具指向这个 .py 文件按顺序添加参数把输出参数的“方向”设成 Output类型按数据源设成 Feature Class 或 Raster Dataset。第三步在 ModelBuilder 里把工具拖进模型前后接上其他工具输出变量可以直接连到下一个工具的输入。挂上去之后有一类错误特别隐蔽参数顺序改了但脚本里的下标没跟着改工具照样能跑结果张冠李戴。我的做法是在脚本开头把每个参数原样打一遍gp.AddMessage(str(in_fc))跑一次看结果窗口确认取值对得上再往下走。后面再改主要改两处一是把tmp_buf.shp这种中间文件改成用in_memory或者临时目录避免污染工作空间二是给关键步骤套 try/except出错时gp.AddError()把上下文写进消息队列而不是让工具直接红叉了事。地理处理脚本的价值不在于一次跑通而在于三个月后别人接手时还能看懂它为什么这么写。从那以后我每次把脚本挂成工具之前都强制先用GetParameterAsText版本在 PythonWin 里空跑一遍参数随便填个测试值看消息窗口的输出顺序对不对——这个习惯至少帮我省掉了十几次“工具能跑但结果是错的”的返工。希望帮到你。本文还有配套的精品资源点击获取