资讯动态

ArcGIS Python脚本自动化:批处理、游标与工具封装避坑

发布时间:2026/10/29 19:03:13 来源:尧图企业网站定制
简介面向ArcGIS初学者与地理信息从业者的入门文档围绕如何在ArcGIS环境中用Python脚本替代重复手工操作降低地理处理自动化的上手门槛。资源包仅含1个docx文件约490KB体量轻便适合通勤或课间快速通读。内容按两条主线展开前半部分梳理Python数学运算符、字符串操作、模块导入、def函数、if/while/for流程控制及简单输入输出后半部分进入ArcGIS集成讲解Geoprocessor对象的创建与帮助查询、Lists参数组织、Toolbox与别名调用、ModelBuilder中嵌入脚本、PythonWin断点调试以及Describe、Exists和地图代数在脚本中的用法。目录由浅入深示例与工具说明穿插便于对照练习并逐步搭建自己的处理脚本。目前已有1492人学习适合零基础GIS用户和需要补强脚本能力的学生作为入门参考。1. 从点到脚本ArcGIS 里的 Python 脚本到底解决什么问题手上有一百个 shp 要重投影、要裁剪到同一个研究区、要按同一套规则算面积鼠标点一遍两小时第二天换个目录还得再点一遍——这是绝大多数人开始学 ArcGIS 中 Python 脚本的真实起点不是想学编程是不想再点鼠标。这份资料的价值在于它没有一上来就丢公式而是先把 Python 的运算符、字符串、模块、函数、流程控制过一遍再落到地理处理对象、工具别名、Lists/Describe、游标和地图代数是一条从语法到真干活的完整链路。适合刚摸 ArcGIS 脚本、手头压着一堆重复处理任务的人也适合写过几段脚本、但总在环境、别名、参数转换上翻车的人前六节可以快速跳读后四节值得逐字看。2. 先把 Python 地基打对ArcGIS 脚本里最容易翻车的六个语法点这一章看着像语法复习其实是后面所有报错的源头。我见过太多脚本逻辑全对最后死在5/2等于 2、死在路径里的反斜杠、死在sys.argv进来的字符串没转浮点。下面六个点按原料的顺序走每个点我都补了在 GIS 场景里真正会咬人的那一面。代码示例沿用老版本的 print 写法不带括号挪到新解释器里要补括号这一点先记住。2.1 数学运算符整型和浮点型的隐性差异Python 的常用运算符就那几个 - * / ** %。规则只有一条但极其要命——参与运算的只要有一个浮点型结果就是浮点型全是整型结果才是整型。这条规则放到 GIS 里就是灾难算坡度时用垂直距离除以水平距离两边都是整数米结果直接归零你还以为是数据坏了。输入表达式结果说明235整型结果2.35.0有一个是浮点型结果就是浮点型5/22两边都是整型小数被直接截掉5./22.5改成浮点型才保留小数5%21取模除完的余数270180再%36090方位角加 180 逆转方向后做角度归一5**225幂运算取模那个例子值得单独说。方位角做 180 度翻转加完可能超过 360用%360一步就归一到 0 到 359 之间不用写 if 判断。这是脚本里处理角度、经度环绕最省事的写法。math模块补的是运算符给不了的东西log10、log、pi、sin/cos/tan、hypot、sqrt。注意三角函数吃的是弧度不是角度这是新手第一个必踩的坑。import math # 三角函数要弧度制先把角度换算过去 degrad math.pi / 180 print math.sin(45 * degrad) # 0.707106781187 print math.cos(90 * degrad) # 1.0 附近浮点误差忽略 # 两点间距离三种写法结果一致 x1, y1 520382, 4152373 x2, y2 520475, 4152963 xr, yr x2 - x1, y2 - y1 print math.hypot(xr, yr) # 597.28... print math.sqrt(xr**2 yr**2) # 同上 print (xr*xr yr*yr) ** 0.5 # 同上不用 import 也能算逻辑说明math.hypot内部做了溢出保护坐标差值很大时比手写平方和更稳**0.5开方虽然不用导入模块但可读性差工程代码里我一般还是用sqrt。参数上degrad就是pi/180这个常量sin只接受弧度值传角度进去结果一定错且错得很安静——不会报错只是结果不对这种最难查。2.2 字符串切片、转义和路径拼接字符串下标从 0 开始切片是含头不含尾这两条记住后面拼路径、截文件名全靠它。GIS 脚本里字符串用得最多的地方不是文本处理是路径和 SQL 表达式。s zhulj print s.capitalize() # Zhulj print s[0] # z第一个字符 print s[1] # h print s[-1] # j倒数第一个等价于 s[len(s)-1] print s[2:4] # ul从下标 2 取到下标 4 之前 print s[2:] # ulj print s[:5] # zhulj print s * 3 # zhuljzhuljzhulj重复 print s.upper() # ZHULJ print s.isupper() # False # 路径解析find 返回下标split 拆成列表 p d:/work/lu.shp print p.find(.) # 10 plist p.split(/) print plist # [d:, work, lu.shp] # 反斜杠是转义符路径要么加 r要么写双斜杠 print rd:\work\soil.shp # d:\work\soil.shp逻辑说明split(/)得到一个列表plist[-1]就是文件名把.shp换成.tif一行就够这是批处理改扩展名最常用的手法。find找不到字符时返回 -1所以判断路径里有没有某个片段别用if p.find(x)要为真的话 0 也会被判成假老老实实写if p.find(x) 0。转义这块是血泪经验。\n是换行、\是单引号、\\才是反斜杠Windows 路径不加r前缀脚本怎么挂的都不知道。我的习惯是路径统一用正斜杠ArcGIS 认实在要贴 Windows 原始路径前面加r。另外写 SQL 表达式时引号会嵌套比如elev 1000外层单引号内层双引号反了工具就解析不了。2.3 模块、def 和流程控制把「选择」写进自动化模块就是别人的代码库用之前import一行 import 可以带好几个逗号分隔放在程序顶部。地理处理的核心模块是那一个加上sys、os、math、random基本够用。自定义函数用def冒号结尾、缩进是函数体、return给返回值。下面这组角度弧度互转是 ArcGIS 脚本里复用率最高的两行代码建议直接抄进自己的工具库。import math def radians(angdeg): return angdeg * math.pi / 180 def degrees(angrad): return angrad * 180 / math.pi print math.sin(radians(45)) # 0.707106781187 print degrees(math.acos(0.5)) # 60.0流程控制三件套if / while / for的写法都一样条件行冒号结尾下一行缩进。区别在语义——if只走一遍while条件为真就一直转for遍历一个序列。GIS 里最典型的if场景是太阳高度角正午太阳角超过 90 度说明太阳跑到另一侧去了高度角和方位角都得翻。lat 30 # 研究区纬度南半球为负 decl 20 # 太阳倾角夏至 23.44春秋分 0冬至 -23.44 sunangle 90 - lat decl azimuth 180 if sunangle 90: sunangle 180 - sunangle azimuth 0 print sunangle, azimuth逻辑说明sunangle由纬度、太阳倾角推出来超过 90 就做镜像方位角从 180 翻到 0。参数lat和decl是这套算法的全部输入做四季山影批处理时就是把decl循环成 23.44、0、-23.44 三组值。while和for更多用在批量遍历上。下面这段扫目录拿 shp 列表是每个批处理脚本的开头几行。import os ws c:/prog/hmbarea ilist os.listdir(ws) # 目录下所有条目 fcs [] # 空列表装 shp for i in ilist: if i.endswith(.shp): fcs.append(i) for fc in fcs: print fc逻辑说明os.listdir拿到的是文件名列表不带路径endswith做后缀过滤注意大小写敏感.SHP不会被.shp匹配到。append是往列表尾部追加空列表先建好再往里塞别边遍历边改原列表。还有一个常被拿来练手的例子验证正态分布 95% 置信区间import random mu, s 50, 10 z5 mu - s * 1.96 z95 mu s * 1.96 count 0 n 100000 for i in range(n): x random.gauss(mu, s) if x z5 or x z95: count count 1 print float(count) / n # 每次不同稳定在 0.05 附近逻辑说明random.gauss(mu, s)按均值和标准差出随机数循环十万次统计落在区间外的比例。注意最后那句float(count) / n不转浮点的话整型除整型直接得 0前面 2.1 讲的规则在这儿现世报。这个例子本身不干 GIS 的活但它把for、if、random、类型转换串在了一起拿来验环境很合适。另外os.path.exists配if/elif/else是脚本开头做环境自检的标准动作import os.path if os.path.exists(d:/testfolder/test.txt): print 文件存在 elif os.path.exists(d:/testfolder): print 文件夹存在但文件不在了 else: print 两者都不存在有个例子很能说明脚本的价值跟地理处理一点关系没有但 GIS 人必须知道。USGS 的 7.5 分幅 DEM 是文本格式水平坐标单位是米垂直高程单位可能是英尺也可能是米这个标志位藏在文件头第 539 个字符里1是英尺、2是米。不知道这件事拿英尺高程去算坡度结果差 3.28 倍看着还挺像那么回事。import fileinput infile rc:\prog\pendata\woodside.dem firstline fileinput.input(infile)[0] # 读第一行 unitchar firstline[539] # 取第 539 个字符 unit (unknown: not a 7.5 DEM?) if unitchar 1: unit feet if unitchar 2: unit meters print \nElevation in unit fileinput.close()逻辑说明fileinput.input打开文件后按行索引取[0]就是第一行。参数539是写死的偏移换数据源一定要先用文本编辑器数一遍再改别直接套。输出那句拼了换行符和字符串纯粹为了读起来清楚实际脚本里用消息接口更好。2.4 从 sys.argv 到脚本参数外部输入怎么进来前面所有例子都是把参数写死在代码里改一次跑一次。真实自动化必须从外面传参数。最原始的方式是sys.argv列表里第一个是脚本名从第二个开始才是参数且全都是字符串。import sys lat float(sys.argv[1]) decl float(sys.argv[2]) sunangle 90 - lat decl azimuth 180 if sunangle 90: sunangle 180 - sunangle azimuth 0 print 正午太阳角 str(sunangle) print 方位角 str(azimuth)逻辑说明运行脚本时在参数栏里填40 23.44argv[1]拿到 40、argv[2]拿到 23.44不float()转换就全是字符串后面一做减法立刻报类型错误。输出时反过来要str()数字和字符串不能直接加。位置含义进来时的类型用法argv[0]脚本自身路径str一般不用argv[1]纬度strfloat()后参与运算argv[2]太阳倾角strfloat()后参与运算sys.argv在命令行好使但脚本一旦挂进工具箱就不该用它了工具参数的取法换成另一套接口第六章讲。现在只要记住进来的永远是字符串用之前先转类型这一步偷懒后面全是隐式报错。3. 地理处理对象与工具别名脚本调工具的第一道关语法过关之后真正开始调工具。所有地理处理脚本开头都干同一件事——拿到一个地理处理对象后面所有工具、所有环境设置都挂在它身上。这一步没搞对后面写什么都没意义。3.1 创建地理处理对象两种写法的取舍原料给了两种拿对象的方式长得像但适用场景完全不同。# 写法一随桌面端一起装的模块 import arcgisscripting gp arcgisscripting.create(9.3) gp.workspace c:/Tongass gp.clip_analysis(standb4, clipcov, standb4_clip, POLY, 1.25)# 写法二走 COM 派发 import win32com.client gp win32com.client.Dispatch(esriGeoprocessing.GpDispatch.1) gp.workspace c:/Tongass gp.clip_analysis(standb4, clipcov, standb4_clip, POLY, 1.25)逻辑说明两种写法拿到的是同一个对象后面所有调用一模一样差别全在环境依赖上。模块版绑死随桌面端安装的那套解释器解释器版本不能自己升COM 版靠系统注册表找组件可以在别的解释器里跑但位数必须匹配32 位和 64 位对不上就直接报组件找不到。选型上没什么纠结的脚本最终要当工具挂进工具箱用模块版稳、快、不用管注册表临时在外部环境里验证一段逻辑才考虑 COM 版。后续版本把入口统一到一个arcpy模块写法简化成import arcpy然后直接arcpy.Clip_analysis(...)对象那层隐掉了但workspace、overwriteoutput、Describe这些概念一个没变学会老写法再看新接口是降维。注意不要尝试把随桌面端安装的解释器升级到新版本一堆模块是针对特定版本编译好的升完基本等于把环境拆了。3.2 工具箱和别名同名工具怎么区分ArcToolbox 里同一个工具名可能出现在好几个工具箱下。裁剪在 Coverage 那边有一个在数据管理下的栅格那边也有一个处理的数据类型不同。图形界面里你点哪个就是哪个脚本里只有字符串必须靠别名区分。别名就是工具箱的短名已经成了工具全名的一部分写成工具名_别名。查法很土但有效工具箱里右键工具看属性。别名对应工具箱analysisAnalysis ToolsmanagementData Management ToolsconversionConversion Tools3d3D Analyst ToolssaSpatial Analyst ToolscartographyCartography ToolsstatsSpatial Statistics ToolsgaGeostatistical Analyst ToolsarcCoverage ToolslrLinear Referencing Toolsimport arcgisscripting gp arcgisscripting.create(9.3) gp.workspace c:/prog/hmbarea gp.overwriteoutput 1 # 1 表示允许覆盖同名输出 # copyfeatures 属于 Data Management gp.copyfeatures_management(streams/arc, streams.shp) # buffer 属于 Analysis200 是缓冲距离 gp.buffer_analysis(streams.shp, stbuff200.shp, 200) # clip 也属于 Analysis用缓冲结果裁地质线 gp.clip_analysis(geol.shp, stbuff200.shp, geolstr200.shp)逻辑说明三条命令串成一条链——先把 coverage 转成 shp再缓冲 200 米最后拿缓冲面去裁。前三个参数基本都是「输入、参考、输出」的顺序后面才是容差、几何类型之类的可选参数顺序以工具属性里列的顺序为准别凭记忆写。如果一段脚本里反复调同一个工具箱的工具可以省掉每次写别名gp.Toolbox Analysis gp.Buffer(streams.shp, stbuff200.shp, 200) gp.Clip(geol.shp, stbuff200.shp, geolstr200.shp)逻辑说明设了Toolbox之后工具名可以省别名但只在这一个工具箱里有唯一同名工具时才安全跨工具箱混用还是老老实实写全名。3.3 Lists、Describe、Exists先摸清数据家底再动手批处理脚本的第一段永远不是处理是盘点。工作空间里到底有几个要素类、字段叫什么类型、坐标系是什么这些信息拿不到后面就是盲写。ListFeatureClasses按通配符和要素类型筛选返回一个可迭代的列表# 拿工作空间里所有以 w 开头的面要素 fcList gp.ListFeatureClasses(w*, polygon)参数说明第一个是通配符*代表任意不传就是全部第二个是要素类型可选点、线、面、注记等不传也是全部。这个方法的官方签名里两个参数都是可选的。数据类型的多样性直接影响你该用哪个 List 方法。同一个「要素」可能是单个 shp、可能是地理数据库里的要素类、也可能是 coverage 里的弧段或多边形。遍历 coverage 要用数据集列表不能用要素类列表这是很多人第一次跑批处理发现「一个都没列出来」的原因。ListFields加Describe是配套动作一个拿字段清单一个拿数据本身的属性。import arcgisscripting gp arcgisscripting.create(9.3) gp.workspace c:/prog/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表示全部循环出来的是字段对象带Name、Type、精度、小数位这些属性。describe返回的对象属性随数据类型变——要素类有ShapeType、SpatialReference、Extent栅格有MeanCellHeight、Format共同的是DataType。写脚本时先print dsc.DataType确认拿到的是什么东西再取具体属性能省掉一大半「属性不存在」的报错。Exists判断数据在不在返回值是布尔。它和os.path.exists不是一回事前者认地理数据库里的数据集后者只认文件系统路径。if gp.exists(c:/prog/hmbarea/landuse): print 数据集存在 else: print 数据集不存在后续步骤跳过逻辑说明批处理里必须先用它挡一道否则中间某一步失败后面会连锁报一堆看不懂的错。放在循环里就是逐条自检放在开头就是环境预检。3.4 工作空间和 overwriteoutput先把规矩立好workspace是所有相对路径的基准目录工具里只写文件名时就落到它下面去。这一条设错脚本会安静地把结果写到别的地方你在输出目录里翻半天找不到文件还以为工具没执行。overwriteoutput是覆盖开关默认是关的。关着的时候第二次跑同一个脚本输出已存在就报错退出。批处理脚本第一行就把它打开是常规操作。gp arcgisscripting.create(9.3) gp.workspace c:/prog/hmbarea # 相对路径的基准 gp.scratchWorkspace c:/prog/temp # 中间结果落哪儿 gp.overwriteoutput 1 # 允许覆盖同名输出逻辑说明scratchWorkspace管的是工具内部产生的临时数据别让它默认落在系统临时目录里磁盘满了排查起来很痛苦。这三个设置建议做成一个初始化函数每个脚本开头调一次比散落在各处的赋值好维护。提示overwriteoutput打开之后同名输出会被无声覆盖。批处理里如果输入和输出同名比如原地重算字段先备份或者把输出名加后缀别问我怎么知道的。4. 数据管理、游标与地图代数脚本真正干活的地方前三章是装配这一章是开火。批处理遍历、属性表逐行读写、栅格表达式计算三件事覆盖了日常脚本八成的使用场景。4.1 数据管理工具的批处理骨架批处理的通用结构就四步定目录、列清单、循环、输出。下面是骨架换成投影、裁剪、格式转换都一样套。import arcgisscripting, os gp arcgisscripting.create(9.3) gp.overwriteoutput 1 inws c:/prog/hmbarea outws c:/prog/hmbarea_out # 输出目录不存在就先建 if not os.path.exists(outws): os.makedirs(outws) gp.workspace inws fcList gp.ListFeatureClasses(, polygon) for fc in fcList: outfc outws / fc gp.copyfeatures_management(fc, outfc) gp.AddMessage(已处理: fc)逻辑说明ListFeatureClasses是基于workspace迭代的循环里拿到的就是纯名字拼输出路径时手动加上目录。AddMessage每处理一条打一行跑长任务时这是唯一的进度反馈不然你不知道卡在第几个。参数说明copyfeatures_management只有输入和输出两个必填参数输出路径带不带扩展名都行工具会按格式环境补如果要做重投影换成投影工具多传一个坐标系参数其余不变。这段骨架有个容易被忽略的点循环体里不要修改fcList本身也不要中途改gp.workspace。工作空间是所有相对路径的基准循环里一改后半段的输出全落到别处而且不报错。4.2 Cursors逐行读写属性表工具解决不了的精细活得靠游标一行一行来。三个游标分工明确只读用搜索游标读改都用更新游标纯插入用插入游标。游标的标准用法是「打开、取第一行、循环处理、取下一行」直到取到空值为止。rows gp.UpdateCursor(landuse.shp) row rows.Next() while row: # 取值用字段名赋值用 SetValue area row.GetValue(Shape_Area) row.SetValue(面积公顷, area / 10000.0) rows.UpdateRow(row) # 改完必须写回否则白改 row rows.Next() del rows # 用完释放否则文件被占住逻辑说明Next()返回一行取完返回Nonewhile row就是靠这个退出。GetValue/SetValue既能传字段名也能传字段索引字段名可读性好索引快字段多的时候用索引。UpdateRow是把改完的行写回数据集漏了这句循环里算得再对文件里一个值都不会变。del rows这一行别省。游标不释放数据集会被一直占用之后想删除或者重命名这个文件系统直接告诉你被别的程序打开。这是我在批处理脚本上翻过最多次的车后来养成习惯每个游标写完立刻释放或者放进能自动释放的上下文里。参数说明UpdateCursor(数据名, 字段列表, SQL 表达式)字段列表传了就只返回这几列能明显提速SQL 表达式用来过滤行比如只处理某个字段非空的记录语法跟查询对话框里写的一样。4.3 地图代数栅格计算在脚本里怎么写栅格运算不能直接用 Python 的加减乘除——栅格不是数字是数据集。正确做法是把整个表达式写成字符串交给地图代数工具去解析工具返回的是新栅格。# 用空间分析扩展前先签出不签出会报扩展未启用 gp.CheckOutExtension(spatial) # 表达式整体是个字符串内部引号要转义 expr elev 1000 gp.SingleOutputMapAlgebra_sa(expr, c:/prog/out/high_areas)逻辑说明表达式里引用的图层名或字段名用双引号包起来外层字符串用单引号避免一起转义。输出路径不带扩展名时格式由环境设置决定要指定格式就在输出名里写清楚。工具名后缀_sa就是空间分析那个别名具体名字以你当前版本里工具属性显示的别名为准。参数说明单输出地图代数只有一个表达式和一个输出适合一条公式算一个结果需要一次性产出多个栅格的分支逻辑得用多输出那个版本或者拆成几条单输出分别跑可读性反而更好。签出扩展这一步必须放在所有栅格运算之前放到后面无效。栅格和矢量在脚本里的处理思路差别很大矢量工具是一条命令处理一个要素类栅格运算是一条表达式处理一张图表达式的组合能力才是它的价值。同一段表达式里嵌套条件、重分类、邻域统计都可以能把一串手动操作压成一行。4.4 把脚本组织成能反复跑的结构写到这儿单个知识点都通了但脚本会不会变成一坨取决于结构。我的习惯是固定五段参数区、环境区、检查区、处理区、消息区。参数区只放路径和常量环境区只放工作空间、覆盖开关、扩展签出检查区用Exists把该有的东西挡一遍处理区纯干活消息区统一AddMessage。# 1) 参数 inws c:/prog/hmbarea outws c:/prog/hmbarea_out # 2) 环境 gp.workspace inws gp.overwriteoutput 1 gp.CheckOutExtension(spatial) # 3) 检查 if not gp.exists(inws): gp.AddError(输入工作空间不存在: inws) raise SystemExit # 4) 处理 # ...工具调用和游标... # 5) 消息 gp.AddMessage(全部完成)逻辑说明这个骨架的好处是排错时能一眼定位阶段报错信息里带的是哪一段就很清楚是环境问题还是数据问题。raise SystemExit比往下硬跑好输入都没有还继续执行只会产生一堆无意义的报错盖住真正的问题。参数上inws和outws是唯二需要改的其余都是常量。养成这个结构之后写第二个脚本直接复制骨架改两个路径就能跑比每次从空白文件开始快得多。5. 避坑与排查脚本跑不通时先看这五处报错信息通常只告诉你结果不告诉你原因。下面五条是我和周围人反复踩过的按「现象、原因、解决」写照着对一遍能省掉大半排查时间。5.1 现象执行到工具那一行直接崩提示找不到工具或命令原因基本只有一个——工具别名没写或者写错。图形界面里点习惯了写脚本时以为Buffer直接能调实际要么补上_analysis要么先设好gp.Toolbox。同名工具跨工具箱时更明显脚本里不给别名解释器不知道你指哪个。解决别凭记忆写工具名。在工具箱里右键工具看属性别名那一栏写得清清楚楚复制过来。不确定的话先拿最小数据集跑一条命令验证跑通再往脚本里塞。另外工具名大小写在部分版本里不敏感但别名是敏感的Analysis和analysis是两回事统一小写最保险。5.2 现象脚本跑完没报错但结果数值明显不对坡度一片 0、面积差好几个数量级原因有两层。浅层是整型除法两个整数一除小数被截掉坡度 0 度、比例 0看着像数据坏了。深层是单位不统一垂直高程用英尺、水平坐标用米算出来的坡度差 3.28 倍比第一个更难发现因为它不是 0是一个看起来很合理的错值。解决所有除法先把被除数或除数写成浮点5.比float(5)短我一般直接加点。单位问题在脚本开头统一换算高程是英尺就乘 0.3048或者干脆把 Z 因子设进环境里。凡是涉及高程、坡度、体积的脚本结果出来先手工核对一个样本别信脚本。5.3 现象第一次跑成功第二次直接报输出已存在、任务中止原因覆盖开关没打开。工具默认不覆盖输出目录里已经有同名文件工具直接退出。更麻烦的一种是部分成功——前几步覆盖了后几步卡住目录里一半新一半旧。解决脚本开头显式gp.overwriteoutput 1。如果业务上确实不该覆盖比如原始成果就别开这个开关改成输出名带日期或版本后缀让每次结果都可追溯。两种做法都行唯独不要「有时候开有时候不开」那样出的问题最难复现。注意覆盖开关打开后同名输出是无提示替换的输出目录里别放你不能丢的东西。5.4 现象脚本里写了中文注释或者中文路径工具直接报编码错误、文件读不到原因脚本文件本身的编码和解释器默认编码不一致中文注释在读取阶段就崩了还没轮到工具执行。路径带中文更容易出事某些工具内部会把路径转成别的编码转完就对不上了。解决脚本存成纯英文注释最稳非要写中文就在文件头加编码声明。路径统一用正斜杠能不用中文目录就不用中间结果一律落在纯英文路径下。这种问题排查起来特别烦因为报错信息指向的行号往往不是真凶是后面好几行。5.5 现象属性表改完了文件删不掉、重命名失败或者再打开还是旧值原因游标没释放。游标打开会持有数据集的锁脚本走完了但对象还在内存里锁就一直不放。更隐蔽的是改完没调UpdateRow循环里算得热火朝天文件里一个值没动。解决每个游标用完立刻释放别指望脚本退出自动回收。改值的地方SetValue后面紧跟UpdateRow两句成对出现。批量更新前先在三个要素的小数据集上跑一遍确认值真的落盘了再上全量。6. 从脚本到工具封装、调试与最后的自检零散脚本和「工具箱里的一个工具」之间差的是参数接口和消息输出。sys.argv那套只适合命令行挂进工具箱后参数要从工具属性里取输出要通过消息窗口回传否则跑完什么都看不见。import arcgisscripting gp arcgisscripting.create(9.3) # 参数按工具属性里 Parameters 的顺序编号从 0 开始 lat float(gp.GetParameterAsText(0)) decl float(gp.GetParameterAsText(1)) sunangle 90 - lat decl azimuth 180 if sunangle 90: sunangle 180 - sunangle azimuth 0 gp.AddMessage(正午太阳角 str(sunangle)) gp.SetParameterAsText(2, str(sunangle)) # 输出参数回填 gp.SetParameterAsText(3, str(azimuth))逻辑说明GetParameterAsText按索引取索引就是你在这个脚本工具的属性里加参数的顺序改顺序等于改接口前面调它的模型全废。回填用SetParameterAsText这样输出能作为下游工具的输入接下去。AddMessage打的消息会进结果窗口这是脚本运行过程中唯一能看见的东西我把它当黑匣子用每一步都往里写当前状态。调试这块断点、单步、变量观察这些能力要有一个顺手的编辑环境随桌面端装的那个带窗口的解释器就够用。我的做法是先在小数据上跑——三个要素、两张栅格能在一分钟内跑完的那种逻辑对了再换全量。全量跑挂了把中间结果逐级打印出来看是哪一步开始不对比盯着最终结果猜快十倍。最后说个习惯。从那以后我每次把脚本挂进工具箱之前都强制走一遍三件事拿一个空目录从零跑一遍、拿一个已有结果的目录再跑一遍、故意不给一个必填参数跑一遍。第一遍验通第二遍验覆盖第三遍验报错信息看不看得懂。三遍都过了才敢交给别人用因为有问题的脚本一旦变成工具被别人引用后面改接口的成本比写脚本本身还高。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑