搜罗全网!ArcGIS二次开发Python(arcpy)指南(五):你不知道的属性表游标本质和应用

前言:ArcPy 通过游标对象获取、处理矢量数据的属性信息。但游标对象不仅仅局限于 ArcPy,它也是 Python 体系下的,可以是 Pythonic 的,这一节,由浅到深带你了解游标的用法,最后回归游标对象的本质...

游标对象是什么

在 ArcPy 中检索、更新、修改矢量文件属性表是非常常见的操作。而 ArcPy 也提供了3个专门的方法来实现这些功能。首先我们需要了解 ArcPy 中的数据访问模块:da(arcpy) 模块,英文:The data access module,是一个数据处理模块。而就在该模块中有三种游标方法,使用这三种方法可以创建三种不同的游标对象(实例),我们进一步使用游标对象就可以获取、修改、插入属性表中的各种数据。这三个方法首次是在 ArcGIS10.1 版本中加入:arcpy.da.SearchCursor、arcpy.da.UpdateCursor、arcpy.da.InsertCursor。需要注意的是,在 ArcGIS10.1 版本前大家使用的是三个旧的游标方法:arcpy.SearchCursor、arcpy.UpdateCursor、arcpy.InsertCursor。新版的游标比旧版的性能更好,但是为了兼容先前的代码,旧的方法没有被移除,只是不再推荐使用了。也就是说你可以在 ArcGIS10.1 之后的 ArcPy 中同时使用新版游标方法和旧版游标方法。但是由于新版游标的性能更好,另外新旧游标对象各自的方法都有些许差异,所以没有必要去研究和使用旧版游标对象了。游标对象是什么?那么现在回答这个问题:游标对象就是通过执行游标方法而获得的游标对象实例,使用游标对象可以获取属性表数据(包括几何属性)。

新旧游标在处理最多100000个点时的速度对比图,下面的蓝色线表示新游标,绿色表示旧版游标,可以明显看到蓝色线较低,表示耗时较少速度比较图表来源:https://gis.stackexchange.com/questions/108807/how-is-the-data-access-cursor-performance-so-enhanced-compared-to-previous-versiNote:后文提及的游标及其方法均指新版游标和新版方法,请注意。三种游标对象

三种游标对象的使用方法在官方文档里写的很清楚,所以我简单复制一下。除开官方文档外,我会重点讲一下注意事项和游标的本质及其应用。下面是用于演示的矢量文件的初始属性表。

../NYC.gdb/Boroughs 要素的初始属性表1.SearchCursor搜索游标,当然你想叫什么样的中文名都可以,该游标是只读游标,只能查询属性表中信息,不能修改。创建该游标的语法如下:cursor = arcpy.da.SearchCursor (in_table, field_names,{where_clause}, {spatial_reference}, {explode_to_points},{sql_clause})该方法前2个如 in_table 和 field_names 是必选参数,后面4个是可选参数(很少使用到)。第一个参数输入要素类、图层、表或表视图;第二个参数输入字段名称或者令牌,虽然令牌这个说法可能看起来比较怪,其主要用于获取属性表中没有的信息,比如几何的质心、周长、面积等,使用起来也非常简单,和字段名称输入方式一样,加上引号当字符串传进去就好,具体有那些种类的令牌官方文档上写的很清楚。1.1属性fields:返回字段名称参数(几乎根本不会使用)。1.2方法next ():将下一行作为元组返回。字段将按照创建光标时所指定的顺序返回。reset ():将光标重置回第一行。1.3示例代码示例代码可见文件 ../Chapter5/1.SearchCursor.py:# -*- coding:utf-8 -*-import arcpyimport osarcpy.env.overwriteOutput = Truewk_path = os.path.abspath("../NYC.gdb")arcpy.env.workspace = wk_pathfield = ["BoroName", "SHAPE@AREA"] # ▶注释1◀with arcpy.da.SearchCursor("Boroughs", field) as cursor:print cursor.fieldsprint "Next 1: {}".format(cursor.next()) # ▶注释2◀print "Next 2: {}".format(cursor.next())print "Next 3: {}".format(cursor.next())print "Next 4: {}".format(cursor.next())print "Next 5: {}".format(cursor.next())cursor.reset() # ▶注释3◀print "Next 1: {}".format(cursor.next())print "Next 2: {}".format(cursor.next())print "Next 3: {}".format(cursor.next())print "Next 4: {}".format(cursor.next())print "Next 5: {}".format(next(cursor)) # ▶注释4◀输出结果:(u'BoroName', u'SHAPE@AREA')Next 1: (u'Staten Island', 1601777454.0332422)Next 2: (u'Brooklyn', 1956932802.231596)Next 3: (u'Queens', 3030316015.6541715)Next 4: (u'Bronx', 1171019852.6289911)Next 5: (u'Manhattan', 630673101.7271129)Next 1: (u'Staten Island', 1601777454.0332422)Next 2: (u'Brooklyn', 1956932802.231596)Next 3: (u'Queens', 3030316015.6541715)Next 4: (u'Bronx', 1171019852.6289911)Next 5: (u'Manhattan', 630673101.7271129) ▶注释1◀:使用了令牌 SHAPE@AREA,该令牌可以获取每个要素的面积。▶注释2◀:使用游标内置的 next() 方法可以依次遍历属性表内容。▶注释3◀:reset() 重置游标位置,如果再继续使用 next() 方法的话就会报错,因为从上面可以看到Boroughs 属性表中只有5行数据,现在游标已经到了属性表末尾。▶注释4◀:这里使用了 next(cursor),效果和 cursor.next() 一样,next(obj) 是 Python 的内置方法。具体详情可见下面的游标的本质小结。官方在线文档:https://desktop.arcgis.com/zh-cn/arcmap/latest/analyze/arcpy-data-access/searchcursor-class.htm2.UpdateCursor更新游标:该游标是我使用最为频繁的游标,它不仅能遍历属性表,替代搜索(SearchCursor)游标,还能够更新属性表内容。创建该游标的语法如下:cursor = arcpy.da.UpdateCursor (in_table, field_names,{where_clause}, {spatial_reference}, {explode_to_points}, {sql_clause})该游标方法的参数和搜索游标的方法一致,前2个如 in_table 和 field_names 是必选参数,后面4个是可选参数(很少使用到)。2.1属性fields:返回字段名称参数(同样几乎不会使用)。2.2方法next ():将下一行作为元组返回。字段将按照创建光标时所指定的顺序返回。reset ():将光标重置回第一行。除开这两个搜索游标都有的方法外,更新游标有两个自带的独特方法:deleteRow ():删除当前行。updateRow (row):更新表中的当前行2.3示例代码示例代码可见文件 ../Chapter5/2.UpdateCursor.py:# -*- coding:utf-8 -*-import arcpyimport osarcpy.env.overwriteOutput = Truewk_path = os.path.abspath("../NYC.gdb")arcpy.env.workspace = wk_pathfield = ["BoroName", "SHAPE@AREA"]with arcpy.da.UpdateCursor("Boroughs", field) as cursor:for row in cursor:row[0] = row[0] + "_1" # ▶注释1◀# row[0] = row[0][:-2]cursor.updateRow(row) # ▶注释2◀输出结果:

▶注释1◀:在原名字的基础上加上 “_1”。见输出结果。▶注释2◀:任何更改都需要使用 updateRow 方法才能使更改得到落实。官方在线文档:https://desktop.arcgis.com/zh-cn/arcmap/latest/analyze/arcpy-data-access/updatecursor-class.htm3.InsertCursor插入游标:该游标与以上两个游标差别较大。使用该游标来添加新行。创建该游标的语法如下:cursor = arcpy.da.InsertCursor (in_table, field_names)参数只有两个必选参数。3.1属性fields:返回字段名称参数(同样几乎不会使用)。3.2方法insertRow (row):向表中插入一行。3.3示例代码示例代码可见文件 ../Chapter5/3.InsertCursor.py:# -*- coding:utf-8 -*-import arcpyimport osarcpy.env.overwriteOutput = Truewk_path = os.path.abspath("../NYC.gdb")arcpy.env.workspace = wk_pathfield = ["BoroName", "SHAPE@"]cursor = arcpy.da.InsertCursor("Boroughs", field)array = arcpy.Array([arcpy.Point(993701.189, 232208.219),arcpy.Point(976940.744, 245402.664),arcpy.Point(965482.411, 211027.664),arcpy.Point(974162.966, 191583.219)])new_polygone = arcpy.Polygon(array) # ▶注释1◀cursor.insertRow(["test", new_polygone]) # ▶注释2◀cursor.insertRow(["test2", None]) # ▶注释3◀del cursor▶注释1◀:创建了一个几何对象,面 new_polygone;▶注释2◀:使用 insertRow 方法新添加了一行,同时附带了几何对象,输出的结果如下:

新增加了一个几何(高亮部分)▶注释3◀:不用几何对象也能添加新的一行,不过这显然就违背了矢量数据的基本要求,即每条属性对应一个几何形状(对象)。如下图所示,黄色框中的数据行是 ▶注释2◀ 中新增几何形状对应的属性;而紫色框中的数据行则是纯粹的属性,没有任何对应的几何形状。当然不建议新增没有对应几何的数据行,没有意义,这里只是用于演示。

运行示例代码后,属性表新增了两行官方在线文档:https://desktop.arcgis.com/zh-cn/arcmap/latest/analyze/arcpy-data-access/insertcursor-class.htm3.游标的本质

3.1本质好的,众所周知的三种游标终于说完了,现在说说很多人不知道的东西,也是这篇文章的精华所在:游标的本质。游标的本质是什么?语言是苍白的,直接上代码:示例代码可见文件../Chapter5/4.cursor.py:# -*- coding:utf-8 -*-import arcpyimport osfrom collections import Iterable, Iterator, Sequencearcpy.env.overwriteOutput = Truewk_path = os.path.abspath("../NYC.gdb")arcpy.env.workspace = wk_pathl = [1, 2, 3, 4]cursor = arcpy.da.SearchCursor("Boroughs", ["OID@", "SHAPE@"])abcs = (Iterable, Iterator, Sequence)print [isinstance(l, abc) for abc in abcs]# [True, False, True] #Iterable, not Iterator, Sequenceprint [isinstance(cursor, abc) for abc in abcs] # ▶注释1◀# [True, True, False] #Iterable, Iterator, not Sequence# 使用内置函数 iter() # ▶注释2◀it_l = iter(l)t1 = type(l) # <type 'list'>t2 = type(it_l) # <type 'listiterator'>it_cur = iter(cursor)t3 = type(cursor) # <type 'da.SearchCursor'>t4 = type(it_cur) # <type 'da.SearchCursor'>#look at identify of cursor objectsprint id(cursor) # 105692320print id(it_cur) # 105692320从 ▶注释1◀ 可以看到游标是可迭代对象、也是迭代器、不是序列。包括后面的 ▶注释2◀ 也说明了游标是一种迭代器:迭代是数据处理的基石,而按照惰性获取数据项的方式,即按需一次获取一个数据项,这叫迭代器模式(Iterator pattern),而迭代器就负责实现这一模式功能。所以游标拥有迭代器的各种特性,在这个基础之上,我们可以最大化的利用 Python 的优势,写出优美简洁的代码。3.2本质的应用灵活运用迭代器能省下大量的功夫,这里使用一些实例来说明。以下所有示例代码见文件 ../Chapter5/5.sample.py。拆包元组拆包就是迭代器支持的功能之一。可以简化代码,见下面示例代码的 ▶注释1◀ 。# ...field = ["BoroName", "SHAPE@AREA"]with arcpy.da.SearchCursor("Boroughs", field) as cursor:for name, area in cursor: # ▶注释1◀print name惰性释放迭代器是惰性:迭代器不会一次性把所有数据拿到“手上”,而是根据需要,一个一个的拿数据。但是如果我们想要一次性获取所有数据呢?难道要老实的遍历一次,把每一次的数据都装进一个列表?当然不必这样,使用 python 内置函数 list(),可以直接释放惰性。# 惰性释放field = ["BoroName", "SHAPE@AREA"]# <<<传统写法>>> ▶注释1◀new_list = []with arcpy.da.SearchCursor("Boroughs", field) as cursor:for name, area in cursor:new_list.append((name, area))# 将全部数据装进一个列表print new_listdel cursor# <<<<惰性释放写法>>> ▶注释2◀cursor = arcpy.da.SearchCursor("Boroughs", field)new_list2 = list(cursor)print new_list2del cursor▶注释1◀ 这里这是普通的写法,需要先创建一个容器(列表),然后一个一个把内容装进去。而 ▶注释2◀ 位置就是直接使用内置的列表构造函数 list(),直接去除惰性,因为一个列表是完全没有惰性的。当然特定情况下可能需要去除惰性,比如结合 len() 函数快速掌握这个矢量数据有多少个几何形状(属性)。获取极值如何获取某一字段的最大值或者最小值是多少呢?一条属性一条属性的遍历然后比较大小嘛?还是使用 ArcGIS 自带的表达式?其实都不用,一行代码解决问题,# 获取极值from operator import itemgetterfield = ["BoroName", "SHAPE@AREA"]with arcpy.da.SearchCursor("Boroughs", field) as cursor:print max(cursor, key=itemgetter(1))输出结果如下,面积最大的是“皇后区”:(u'Queens', 3030316015.6541715)降序/升序排列通过一个字段值的大小进行降序/升序排列。如果不结合迭代器自身的特性你要怎样实现呢?但是其实也是只需一两行代码就能轻松实现。from operator import itemgetterfield = ["BoroName", "SHAPE@AREA"]with arcpy.da.SearchCursor("Boroughs", field) as cursor:for name, area in sorted(cursor,  key=itemgetter(1), reverse=True):print (name, area)输出结果:(u'Queens', 3030316015.6541715)(u'Brooklyn', 1956932802.231596)(u'Staten Island', 1601777454.0332422)(u'Bronx', 1171019852.6289911)(u'Manhattan', 630673101.7271129)最后为什么 Python 这么流行的原因就是简单、优美,是 Pythonic。在这里我们不局限于 ArcPy 这一个站点包,视野开阔到整个 Python 语言,在了解了游标的本质后我们能轻车熟路的使用很多 Python 内置的函数或者默认库写出优美、简洁的代码,不仅仅局限于上面简单提到的几个案例。结束语

看完本章节,你可以知道:三种游标及其对应创建方法;三种游标的使用方法和区别;游标的本质是迭代器;结合迭代器的特性写出优美的代码;希望你跳出 ArcPy 的局限,将视野放大到 Python 上。使用版本:Windows 10PyCharm 2020.3.3ArcGIS 10.3Python 2.7.8源代码、教学文档离线小册子下载:

(0)

相关推荐