Удаление курсора, используемого в 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.html и help.arcgis.com/ ru / arcgisdesktop / 10.0 / help / index.html # //… . В частности, посмотрите на комментарии @JasonScheirer внизу первой ссылки.
Аарон

Ответы:

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, потому что вы не могу сохранить ваши изменения. Если вы единственный, кто будет затронут проблемой, то во что бы то ни стало бросайте вызов хорошей практике.

jpmc26
источник
3

Нет, нет необходимости удалять cursorпосле использования в понимании. A cursorявляется экземпляром класса, который является объектом (все в python является объектом). У каждого сеанса Python есть namespaceссылка, которая содержит ссылки на все объекты в сеансе - воспринимайте это как словарь, где ключи - это ссылки на каждый объект, а значения - это сами объекты. Когда «количество ссылок» - количество ключей, которые ссылаются на этот объект - падает до нуля, объект удаляется и память перераспределяется . Когда вы используете cursorв понимании, нет ссылки на этот объект в пространстве имен. После того, как понимание сделано, объект будет удален.

Там нет записи в пространстве имен, и, следовательно, не нужно ничего удалять. 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
@ jpmc26, какая часть "крайне плохая практика программирования"? Понимания в целом? Или только в том случае, если повторяемый объект создается в рамках понимания? Я думал, что один сильный аргумент в пользу последнего заключается в том, что он немедленно освобождает ресурс.
Том
@ Том Не освобождает ресурсы явно. Постижения - фантастические инструменты, и создание нормальных итераций внутри них совершенно нормально. Плохо то, что объекты курсора получают блокировки файлов, и их явного освобождения нет. Смотрите мой ответ для более подробной информации.
jpmc26
2

Курсоры обновления и вставки нельзя создать для таблицы или класса объектов, если для этого набора данных существует эксклюзивная блокировка. Сбой функций UpdateCursor или InsertCursor из-за исключительной блокировки набора данных. Если эти функции успешно создают курсор, они применяют монопольную блокировку к набору данных, чтобы два сценария не могли создать обновление или вставить курсор в один и тот же набор данных.

В Python блокировка сохраняется до тех пор, пока курсор не будет отпущен. В противном случае все другие приложения или сценарии могут быть излишне лишены доступа к набору данных. Курсор может быть освобожден одним из следующих:

Включение курсора внутри оператора with, который гарантирует снятие блокировок независимо от того, успешно ли завершен курсор;

Вызов reset () для курсора;

Завершение курсора;

Явное удаление курсора с помощью оператора del в Python - ESRI

Блокировка с помощью курсоров arcpy.da во многом аналогична блокировке с использованием оригинальных курсоров arcpy.

После тестирования вашего кода, и, как указал gberard, после завершения понимания ссылка на курсор отсутствует.
Кроме того, нет никаких блокировок на классе объектов после того, как понимание заканчивается.

jbalk
источник
1
Удаление чего? Там нет ссылки на объект курсора после завершения понимания, поэтому в теории он должен быть закрыт. Будет ли реализация ESRI вести себя так, как вы ожидаете, это другой вопрос, и я не думаю, что документы действительно ответят на это.
mikewatt