ArcPy入门学习指南(含:arcpy in_memory的详细解答)
很多团队在做 ArcGIS 地理处理时,最头疼的是“明明只是临时中间结果,却要频繁落盘到 GDB 或 Shapefile,速度慢、磁盘乱”。作为长期做 Python 与地理处理自动化的从业者,我的经验是:合理利用 ArcPy 的 in_memory 工作空间,可以显著减少磁盘 I/O、提速流水线,还能让脚本更整洁、可维护。

ArcPy 与 in_memory:是什么
ArcPy 是 ArcGIS Pro/ArcMap 提供的 Python 地理处理接口,覆盖数据管理、分析、制图与自动化。in_memory 工作空间可以理解为一个“驻留内存的虚拟地理数据库”,在 Python 进程生命周期内存在(会话结束即释放),支持大多数地理处理工具的中间结果存取(表与要素类为主)。
用一个类比:如果把整条分析流程比作装配线,那么磁盘上的文件就像仓库货架,上架/下架都要搬运;而 in_memory 更像是工作台上的临时托盘,拿取与放回几乎零搬运(I/O),速度自然快。
为什么要用 in_memory
- 性能:减少磁盘读写,常见缓冲、叠置、字段计算等场景可显著缩短耗时。
- 整洁:中间结果不落盘,避免临时数据污染工程目录。
- 可组合:链式调用更顺滑,便于快速搭建与迭代分析流水线。
- 资源亲和:内存可就地复用对象,减少碎片化读写。
核心提示:in_memory 适合“中间态、可丢弃”的临时数据。对需要持久化、复查或共享的成果,仍应及时 CopyFeatures 到文件地理数据库。
基本用法与代码模板
以下示例以 ArcGIS Pro 环境为参考,演示把中间结果放到内存、最终结果落盘的常见模式。
# -*- coding: utf-8 -*-
import arcpy
import time
# 环境配置
arcpy.env.overwriteOutput = True # 允许覆盖输出(谨慎使用)
arcpy.env.workspace = "in_memory" # 把当前工作空间设置为内存
# 输入与输出
in_fc = r"C:datatransport.gdbroads"
out_fc = r"C:dataoutput.gdbroads_buf_diss"
t0 = time.perf_counter()
# 1) 在内存中做缓冲
buf_fc = "roads_buf" # 因为 workspace= in_memory,可直接用名称
arcpy.analysis.Buffer(in_fc, buf_fc, "50 Meters", dissolve_option="NONE")
# 2) 在内存中溶解以减少冗余
diss_fc = "roads_buf_diss"
arcpy.management.Dissolve(buf_fc, diss_fc)
# 3) 最终结果落盘到文件地理数据库
arcpy.management.CopyFeatures(diss_fc, out_fc)
print(f"流程耗时:{time.perf_counter() - t0:.2f}s")
# 4) 清理内存中的中间结果(可选)
arcpy.management.Delete([buf_fc, diss_fc])
要访问内存中的对象,可用 in_memory/名称 的显式路径,或通过 arcpy.EnvManager 暂时切换工作空间:
# 显式路径写法
arcpy.Exists("in_memory/roads_buf")
# 上下文管理器写法,便于枚举删除
with arcpy.EnvManager(workspace="in_memory"):
for fc in arcpy.ListFeatureClasses():
arcpy.management.Delete(fc)
创建唯一临时名称与存在性检查
避免命名冲突是稳定自动化的关键。推荐结合 CreateUniqueName 与 Exists:
tmp_fc = arcpy.CreateUniqueName("tmp", "in_memory") # 自动生成不重复名称
arcpy.analysis.Buffer(in_fc, tmp_fc, "100 Meters")
if arcpy.Exists(tmp_fc):
cnt = int(arcpy.management.GetCount(tmp_fc)[0]) # 获取要素数量
print(f"临时要素数:{cnt}")
与数据访问模块(arcpy.da)的配合
在内存要素类上使用 arcpy.da 游标,可避免额外磁盘读写:
# 统计内存缓冲结果的面积总和(投影坐标系下)
total_area = 0.0
with arcpy.da.SearchCursor("in_memory/roads_buf", ["SHAPE@AREA"]) as cur:
for row in cur:
total_area += row[0]
print(f"缓冲区总面积:{total_area:.2f}")
性能对比的最小实验
下面给出一个可复现的“小基准”,比较 in_memory 与地理数据库输出的速度(以缓冲为例):
import time
import arcpy
arcpy.env.overwriteOutput = True
in_fc = r"C:datatransport.gdbroads"
# A) in_memory
t0 = time.perf_counter()
arcpy.analysis.Buffer(in_fc, "in_memory/roads_buf", "30 Meters")
t_inmem = time.perf_counter() - t0
# B) FileGDB
t1 = time.perf_counter()
arcpy.analysis.Buffer(in_fc, r"C:datascratch.gdbroads_buf", "30 Meters")
t_gdb = time.perf_counter() - t1
print(f"in_memory:{t_inmem:.2f}s, GDB:{t_gdb:.2f}s")
在典型机械盘或网络盘环境中,in_memory 往往有明显优势;SSD 上收益依然存在,但幅度会随数据量与工具类型而变化。
最佳实践与清理策略
- 只把中间结果放内存:可丢弃的数据放 in_memory,阶段性成果及时 CopyFeatures 到 GDB。
- 控制名称生命周期:用
CreateUniqueName或时间戳命名,避免覆盖与串扰。 - 显式删除:流程末尾
arcpy.management.Delete清理,长管线中分段清理降低峰值内存。 - 分块处理:超大数据按网格/行政区切块到内存处理,阶段成果落盘,再汇总。
- 失败兜底:异常时也要清理,结合 try/finally 确保 Delete 执行。
# try/finally 保障清理
tmp1, tmp2 = "in_memory/a", "in_memory/b"
try:
arcpy.analysis.Buffer(in_fc, tmp1, "100 Meters")
arcpy.management.Dissolve(tmp1, tmp2)
arcpy.management.CopyFeatures(tmp2, out_fc)
finally:
for ds in (tmp1, tmp2):
if arcpy.Exists(ds):
arcpy.management.Delete(ds)
常见问题与易错点
- 支持的数据类型:以要素类与表为主;对栅格数据集的直接写入通常不受支持(请落盘到 GDB/TIFF,或使用栅格对象工作流)。
- 路径写法:统一使用
in_memory/名称,或把arcpy.env.workspace设为in_memory后用短名。 - 会话生命周期:Python 进程结束即释放;ArcGIS Pro 崩溃或重启后内存数据不可恢复。
- 内存限制:32 位环境(如老版 ArcMap)受限更明显;64 位 ArcGIS Pro 更宽裕,但大数据仍需分块。
- 并行与多进程:ArcPy 通常不线程安全;若用多进程,每个子进程有独立 in_memory 命名空间,注意避免跨进程引用。
- OverwriteOutput:开启覆盖输出有助迭代,但要确保目标名不会被误覆盖关键数据。
- 投影与度量:涉及面积/长度计算前,先投影到合适的等积/等距坐标系,再在内存中计算。
典型场景选择建议
| 场景 | 是否优先用 in_memory | 备注 |
|---|---|---|
| 缓冲/叠置/选择等中间结果 | 是 | 链式操作快,减少 I/O |
| 最终成果产出/归档 | 否 | 落盘到 GDB 或企业级数据源 |
| 海量数据(> 数百万要素) | 视内存而定 | 建议分块,阶段性落盘 |
| 栅格分析 | 通常不适用 | 请使用栅格对象或文件输出 |
小案例:一次性分析脚本的“内存优先”重构
目标:对站点要素进行 300m 缓冲,求与地块相交面积,并输出 TOP10 结果。除最终表外,全部放在内存中进行。
# 输入
sites = r"C:projcity.gdbpoi_station"
parcels = r"C:projcity.gdbparcels"
out_table = r"C:projresult.gdbpoi_parcel_top10"
arcpy.env.overwriteOutput = True
arcpy.env.workspace = "in_memory"
# 1) 站点缓冲(内存)
buf = "sites_buf"
arcpy.analysis.Buffer(sites, buf, "300 Meters", dissolve_option="NONE")
# 2) 与地块相交(内存)
inter = "buf_parcel_inter"
arcpy.analysis.Intersect([buf, parcels], inter)
# 3) 计算相交面积(新增字段,内存)
arcpy.management.AddField(inter, "A_m2", "DOUBLE")
arcpy.management.CalculateField(inter, "A_m2", "!shape.area@SQUAREMETERS!", "PYTHON3")
# 4) 汇总每个站点的相交面积(内存)
stat_tbl = "stat_by_site"
arcpy.analysis.Statistics(inter, stat_tbl, [["A_m2","SUM"]], case_field="SITE_ID")
# 5) 选出 TOP10 并落盘
# 说明:内存表可作为 Select 工具输入,结果落盘到 GDB
top10_tbl = "top10"
arcpy.management.SelectLayerByAttribute # 占位说明:如需更复杂排序/取前N,可落盘后用 SQL 处理
arcpy.management.CopyRows(stat_tbl, out_table) # 简化:此处可替换为排序+取前N的具体实现
# 6) 清理(可选)
for ds in [buf, inter, stat_tbl, top10_tbl]:
if arcpy.Exists(ds):
arcpy.management.Delete(ds)
上例突出一个重构思路:把所有可丢弃的中间态留在内存,I/O 最后一跳再落盘。实际项目中可将“排序取前 N、字段派生”等逻辑进一步完善。
进阶建议:与 scratchGDB 搭配
当中间结果需要短暂持久化(例如跨会话复用、人工复核),可将关键阶段输出写入 arcpy.env.scratchGDB,其余仍留在 in_memory:
arcpy.env.scratchGDB # 系统临时地理数据库路径
key_stage = arcpy.CreateUniqueName("stage1", arcpy.env.scratchGDB)
arcpy.management.CopyFeatures("in_memory/roads_buf_diss", key_stage)
结语
总结来说,在 ArcPy 自动化中优先采用 in_memory 承载中间结果,是“既快又稳”的工程化选择:一方面显著减少 I/O 加速流程,另一方面通过命名规范与清理策略保证脚本结构清晰、资源安全。你在自己的项目里,最想把哪段“慢得让人抓狂”的流程改造成内存优先?欢迎留言交流,也可访问 GIS研习社(gisyxs.com)获取更多实践案例。
参考文献
- Esri. The in-memory workspace — ArcGIS Pro documentation. https://pro.arcgis.com/en/pro-app/latest/help/analysis/geoprocessing/basics/the-in-memory-workspace.htm
- Esri. Buffer (Analysis). https://pro.arcgis.com/en/pro-app/latest/tool-reference/analysis/buffer.htm
- Esri. Dissolve (Data Management). https://pro.arcgis.com/en/pro-app/latest/tool-reference/data-management/dissolve.htm
- Esri. Delete (Data Management). https://pro.arcgis.com/en/pro-app/latest/tool-reference/data-management/delete.htm
- Esri. CreateUniqueName (arcpy). https://pro.arcgis.com/en/pro-app/latest/arcpy/functions/createuniquename.htm
- Esri. Exists (arcpy). https://pro.arcgis.com/en/pro-app/latest/arcpy/functions/exists.htm
- Esri. ListFeatureClasses (arcpy). https://pro.arcgis.com/en/pro-app/latest/arcpy/functions/listfeatureclasses.htm
- Esri. Overwrite Output (Environment setting). https://pro.arcgis.com/en/pro-app/latest/tool-reference/environments/overwrite-output.htm
-
大型GIS项目代码管理混乱?如何搞定GitLab中文官网下载与配置!(附:环境部署与分支策略图解) 2026-02-21 08:30:01
-
GIS项目团队协作混乱,Git与GitHub官网入门实操指南(附:分支管理策略) 2026-02-20 08:30:02
-
Scrapy框架真的过时了吗?GIS数据采集实战指南(附:逆向与清洗技巧) 2026-02-20 08:30:02
-
城乡规划GIS项目迁移Git遇阻?Gitee平台代码协同避坑指南(含:操作要点) 2026-02-20 08:30:02
-
GIS项目Git版本失控?手把手教你配置GitHub中文官网入门(含:分支管理策略) 2026-02-20 08:30:02
-
GIS项目代码版本失控?Git入门必学这四招!(含:Gitee官网操作指南) 2026-02-20 08:30:02
-
GitHub项目代码一团乱,GIS协作开发怎么理?(附:分支管理规范) 2026-02-20 08:30:02
-
GIS协作项目Git版本混乱怎么回退?超实用回滚与分支管理策略(含:中文社区经验贴) 2026-02-20 08:30:02
-
Git协同GIS项目版本混乱怎么办?附:GitHub中文版代码冲突解决实战指南 2026-02-20 08:30:02
-
GIS团队代码管理混乱?手把手教你配置GitLab私有仓库(附:环境部署清单) 2026-02-20 08:30:02
-
手机GitHub下载资源无法同步到本地?GIS项目代码版本管理怎么办?(附:Git手机端配置详解) 2026-02-20 08:30:02
-
Scrapy爬虫怎么读?GIS数据采集实战教学(附:坐标转换代码) 2026-02-19 08:30:02
-
Scrapy爬虫抓取受阻?GIS数据反爬策略全解析(含:实战代码) 2026-02-19 08:30:02
-
Scrapy爬虫频繁被封IP怎么办?GIS数据采集实战技巧(附:反爬策略清单) 2026-02-19 08:30:02
-
Scrapy爬虫抓取GIS数据总被封?反反爬策略与代理池实战(附:完整代码) 2026-02-19 08:30:02
-
Scrapy爬取的GIS数据坐标总是偏移?教你用Proj4进行投影转换(附:坐标系速查表) 2026-02-19 08:30:02
-
Scrapy爬虫抓取的数据如何快速转为GIS矢量图层?(附:空间坐标自动匹配脚本) 2026-02-19 08:30:02
-
GIS数据采集效率低?Scrapy爬虫实战教程(含:反爬策略与地理编码技巧) 2026-02-19 08:30:02
-
Scrapy爬虫框架如何应用于GIS数据采集?(附:国土空间规划数据实战案例) 2026-02-19 08:30:02
-
Scrapy爬虫采集GIS数据太慢?教你配置异步并发与代理(含:反爬策略) 2026-02-19 08:30:02