删除字典理解范围内SearchCursor中使用的光标?


12

如果最好使用with语句打开游标以确保将其删除,如下所示:

with arcpy.da.UpdateCursor(fc,fields) as cursor:

然后,如果将游标用作像这样的理解中的可迭代对象:

d = {k:v for (k,v) in arcpy.da.SearchCursor(fc,fields)}

在理解中使用光标后是否有必要删除它?


1
好问题。您是否要处理模式锁?尽管我在新的da游标上找不到确切的来源,但在类似主题上有一些早期(多数已过时)的帖子:sgillies.net/2011/02/01/get-with-it.htmlhelp.arcgis.com/ zh / arcgisdesktop / 10.0 / help / index.html#//…。特别要注意的是,在第一个链接底部查看@JasonScheirer的评论。
亚伦

Answers:


13

是否绝对必要是一个错误的问题。问题是这是否是一个好主意。

通常,在编程中,您应该避免做奇怪的事情,并使用最好的工具来完成工作。如果某事物具有显式释放资源的方式,则只需使该释放显式完成即可:

with arcpy.da.UpdateCursor(fc,fields) as cursor:
    d = {k: v for (k,v) in cursor}

您可能不知道的是,该with子句实际上调用了其他逻辑。甲with子句需要的上下文管理器,它必须有一个__enter__(在输入块时调用)和__exit__(当退出块调用)方法。特别是,__exit__无论是否发生异常,都将调用该方法,从而确保程序即使出现错误也始终释放资源。这为您的代码提供了有关何时获取资源以及何时释放资源的明确文档,并确保可以尽快释放资源。

相比之下,您实际上不能依靠运行时来为您立即神奇地关闭它。这是因为关闭它的方法是通过调用对象的析构函数,这可能会立即发生,也可能不会立即发生。Python不保证何时调用析构函数,仅保证在对象被垃圾回收时才最终实现。(请参阅此处。)目前,已实现Python,以便在不再引用对象时立即进行操作。但是很容易意外地传播对一个对象的引用,并且Python的运行时可能会改变。

还应考虑长期维护。有没有长期的参考,现在,但是当你需要,以便有修改的代码6个月内会发生什么一个参考?如果有人这样做怎么办?进行更改的人可能不会考虑切换到某个with街区,因为那里还没有人。养成清理资源的习惯,这样的麻烦就少得多了。

您是否真的要将代码与垃圾回收的实现细节联系起来?您是否要经常考虑是否可能通过异常意外传播了引用?不,你没有。想象一下,如果在ArcMap中调用脚本时是否发生了这种情况。仅仅为了释放文件,用户将被迫关闭整个过程。所以不要把自己放在那个位置。显式释放资源。仅仅保存一行代码并不值得带来可能引起问题的风险。上下文管理器是在Python中获取和释放资源的标准机制,并且它们做得很好。

最重要的是,不明确释放它是一个坏主意。

当然,这是假定代码有可能影响其他人,例如将其放在需要其他人运行或维护的脚本中,或者如果您必须完全关闭ArcMap则可能会延迟交付您的工作,因为无法保存您的更改。如果您是唯一一个会受到问题影响的人,那么无论如何您都应该面对良好的实践。


3

不,cursor在理解中使用a 之后不必删除它。A cursor是一个类的实例,它是一个对象(python中的所有对象都是对象)。每个python会话都有一个namespace,其中包含对会话中所有对象的引用-将其视为字典,其中的键是对每个对象的引用,而值是对象本身。当“引用计数”(引用该对象的键的数量)降至零时,将删除该对象并重新分配内存cursor在理解中使用a 时,名称空间中没有对该对象的引用。理解完成后,该对象将被删除。

名称空间中没有条目,因此无需删除任何内容。ESRI在此处的示例2中也说明了此语法。

为了进一步说明,如果您运行:

>>> import arcpy
>>> f = r'C:\Workspace\study_area.shp'
>>> a = arcpy.da.SearchCursor(f, ['*'])

您会看到一个.lock文件出现在目录中(检查文件浏览器)。游标的引用是a,这将使cursor(并因此锁定)持续存在直到a被删除。因此,当您随后运行时:

>>> del(a)

命名空间中的条目将被删除,并且锁将释放(.lock文件将消失)。如果您运行:

>>> t = [i for i in arcpy.da.SearchCursor(f, ['*'])]

您要么看不到锁定文件,要么在命令完成后消失。在名称空间中没有条目的情况下,cursor持久化。t指的是您刚刚创建的列表,而不是cursor用于创建它的列表。

总而言之,您只需要担心cursors当它们在名称空间中具有引用时(即,a如上例所示,将它们分配给变量时)删除。


2
这是极端的编程习惯较差。如果某事物具有明确的释放资源的方式,则可以使用它
jpmc26 '18

@ jpmc26,哪一部分是“极差的编程实践”?一般的理解?还是仅当在理解范围内实例化了iterable时?我认为,后者的一个有力论据是它会立即释放资源。
汤姆(Tom)

@Tom没有显式释放资源。理解是很棒的工具,实例化其中的普通可迭代对象是完全正常的。这里的缺点是游标对象获取文件锁,并且没有显式释放它们。请参阅我的答案以获取更多详细信息。
jpmc26

2

如果该数据集存在排他锁,则无法为表或要素类创建更新和插入游标。由于数据集上的互斥锁,UpdateCursor或InsertCursor函数失败。如果这些函数成功创建了游标,则它们将对数据集应用排他锁,以使两个脚本无法在同一数据集上创建更新或插入游标。

在Python中,锁定将一直持续到释放光标为止。否则,可能会不必要地阻止所有其他应用程序或脚本访问数据集。游标可以通过以下方式之一释放:

将游标包含在with语句内,这将确保释放锁,无论游标是否成功完成;

在光标上调用reset();

游标的完成;

使用Python的del语句显式删除游标-ESRI

使用arcpy.da游标锁定与使用原始arcpy游标锁定几乎相同。

在测试了代码之后,正如gberard所指出的那样,在理解结束之后没有对游标的引用。
此外,理解结束后,要素类上没有锁。


1
删除什么?理解结束后没有对游标对象的引用,因此从理论上讲应该将其关闭。ESRI的实现是否按照您的期望运行是另一个问题,我认为文档并不能真正回答这个问题。
mikewatt
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.