Löschen des in SearchCursor verwendeten Cursors innerhalb des Wörterbuchverständnisses?

12

Wenn es am besten ist, Cursor mit einer with-Anweisung zu öffnen, um sicherzustellen, dass sie gelöscht werden, gehen Sie wie folgt vor:

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

Dann, wenn ein Cursor als Iterable in einem Verständnis wie folgt verwendet wird:

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

Muss der Cursor gelöscht werden, nachdem er im Verständnis verwendet wurde?

J. Flann
quelle
1
Gute Frage. Versuchen Sie, Schemasperren zu behandeln? Es gibt einige frühe (meist veraltete) Posts zu einem ähnlichen Thema, obwohl ich zu den neuen Cursorn keine definitive Quelle finden kann da: sgillies.net/2011/02/01/get-with-it.html und help.arcgis.com/ de / arcgisdesktop / 10.0 / help / index.html # //… . Beachten Sie insbesondere die Kommentare von @JasonScheirer am Ende des ersten Links.
Aaron

Antworten:

13

Ob es absolut notwendig ist, ist die falsche Frage. Die Frage ist, ob es eine gute Idee ist.

In der Regel sollten Sie beim Programmieren seltsame Dinge vermeiden und das beste Werkzeug für den Job verwenden . Wenn es einen expliziten Weg gibt, Ressourcen freizugeben, machen Sie die Freigabe einfach explizit und machen Sie es damit:

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

Was Sie möglicherweise nicht wissen, ist, dass die withKlausel tatsächlich zusätzliche Logik aufruft. Für eine withKlausel ist ein Kontextmanager erforderlich, der eine Methode (bei __enter__Eingabe __exit__des Blocks aufgerufen ) und (beim Beenden des Blocks aufgerufen) haben muss. Insbesondere wird die __exit__Methode unabhängig davon aufgerufen, ob eine Ausnahme aufgetreten ist. Dadurch wird sichergestellt, dass das Programm die Ressource auch bei Fehlern immer freigibt. Dies gibt Ihrem Code eine explizite Dokumentation darüber, wann eine Ressource erworben und wann sie freigegeben wird, und stellt sicher, dass eine Ressource so schnell wie möglich freigegeben werden kann.

Im Gegensatz dazu können Sie sich nicht wirklich darauf verlassen, dass die Laufzeitumgebung sie sofort magisch für Sie schließt. Dies liegt daran, dass das Objekt geschlossen wird, indem der Destruktor des Objekts aufgerufen wird. Dies kann sofort geschehen oder auch nicht. Python übernimmt keine Garantie dafür, wann ein Destruktor aufgerufen wird, sondern nur dafür, dass das Objekt irgendwann müllsammelbar ist. (Siehe hier .) Derzeit ist Python so implementiert, dass es geschieht, sobald kein Verweis mehr auf ein Objekt vorhanden ist. Es ist jedoch leicht, versehentlich Verweise auf ein Objekt zu verbreiten, und die Laufzeit von Python kann sich ändern.

Berücksichtigen Sie auch die langfristige Wartung. Es gibt keinen langfristigen Bezug auf es jetzt, aber was in 6 Monaten passiert , wenn Sie den Code ändern müssen , so dass es ist eine Referenz? Was ist, wenn es jemand anderes tut? Die Person, die die Änderung vornimmt, denkt möglicherweise nicht daran, zu einem withBlock zu wechseln, da noch keiner vorhanden ist. Machen Sie es sich zur Gewohnheit , Ihre Ressourcen zu bereinigen , und Sie werden weitaus weniger Probleme damit haben.

Möchten Sie Ihren Code wirklich an Implementierungsdetails der Garbage Collection binden? Möchten Sie ständig darüber nachdenken müssen, ob Sie möglicherweise versehentlich einen Verweis über eine Ausnahme verbreiten? Nein, tust du nicht. Stellen Sie sich vor, dass dies passiert ist, als das Skript in ArcMap aufgerufen wurde. Der Benutzer wäre gezwungen, den gesamten Prozess zu schließen, nur um die Datei freizugeben. Versetze dich also nicht in diese Position. Geben Sie die Ressource explizit frei. Das Speichern einer Codezeile ist das Risiko von Problemen nicht wert. Kontext-Manager sind der Standardmechanismus für das Erfassen und Freigeben von Ressourcen in Python, und sie machen das sehr gut.

Das Fazit ist, dass es eine schlechte Idee ist, es nicht explizit zu veröffentlichen.

Dies setzt natürlich voraus, dass der Code die Möglichkeit hat, eine andere Person zu beeinflussen, z. B. das Einfügen in ein Skript, das eine andere Person ausführen oder warten muss, oder die Bereitstellung Ihrer Arbeit verzögert sich möglicherweise, wenn Sie ArcMap vollständig schließen müssen Änderungen können nicht gespeichert werden. Wenn Sie der Einzige sind, der von einem Problem betroffen ist, sollten Sie sich auf jeden Fall den guten Praktiken stellen, die Sie wollen.

jpmc26
quelle
3

Nein, es ist nicht notwendig, eine zu löschen, cursornachdem Sie sie in einem Verständnis verwendet hat. A cursorist eine Instanz einer Klasse, die ein Objekt ist (alles in Python ist ein Objekt). Jede Python-Sitzung hat eine, namespacedie Verweise auf alle Objekte in der Sitzung enthält. Stellen Sie sich dies wie ein Wörterbuch vor, in dem die Schlüssel Verweise auf jedes Objekt und die Werte die Objekte selbst sind. Wenn der 'Referenzzähler' - die Anzahl der Schlüssel, die sich auf dieses Objekt beziehen - auf Null fällt, wird das Objekt entfernt und der Speicher neu zugewiesen . Wenn Sie cursorin einem Verständnis ein verwenden, ist im Namespace kein Verweis auf dieses Objekt vorhanden. Nachdem das Verständnis abgeschlossen ist, wird das Objekt gelöscht.

Es gibt keinen Eintrag im Namespace und daher muss nichts gelöscht werden. ESRI veranschaulicht diese Syntax auch in Beispiel 2 .

Zur weiteren Klärung, ob Sie ausführen:

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

Im Verzeichnis wird eine .lock-Datei angezeigt (überprüfen Sie Ihren Dateiexplorer). Der Verweis auf den Cursor lautet a, wodurch die cursor(und daher die Sperre) so lange bestehen ableibt, bis sie gelöscht wird. Also, wenn Sie dann laufen:

>>> del(a)

Der Eintrag im Namespace wird entfernt und die Sperre aufgehoben (die .lock-Datei verschwindet). Wenn du läufst:

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

Entweder wird keine Sperrdatei angezeigt, oder sie wird ausgeblendet, wenn der Befehl ausgeführt wird. Ohne einen Eintrag im Namespace ist der cursornicht persistent. tbezieht sich auf die soeben erstellte Liste, nicht auf die cursor, mit der sie erstellt wurde.

Zusammenfassend müssen Sie sich nur Gedanken über das Löschen machen, cursorswenn sie einen Verweis im Namespace haben (dh wenn Sie sie einer Variablen zugewiesen haben, wie aim obigen Beispiel).

Chris
quelle
2
Dies ist eine äußerst schlechte Programmierpraxis. Wenn etwas eine explizite Methode zum Freigeben von Ressourcen hat, verwenden Sie diese .
jpmc26
@ jpmc26, Welcher Teil ist "extrem schlechte Programmierpraxis"? Verständnis im Allgemeinen? Oder nur, wenn das Iterable innerhalb des Verständnisses instanziiert wird? Ich dachte, dass ein starkes Argument für Letzteres ist, dass es die Ressource sofort freigibt.
Tom
@Tom Ressourcen werden nicht explizit freigegeben. Verständnis ist ein fantastisches Werkzeug, und das Instanziieren von normalen Iterationsdateien ist völlig normal. Schlecht dabei ist, dass die Cursorobjekte Dateisperren erhalten und diese nicht explizit freigegeben werden. Siehe meine Antwort für mehr Details.
jpmc26
2

Für eine Tabelle oder Feature-Class können keine Cursor zum Aktualisieren und Einfügen erstellt werden, wenn für dieses Dataset eine exklusive Sperre vorhanden ist. Die UpdateCursor- oder InsertCursor-Funktionen schlagen aufgrund einer exklusiven Sperre für das Dataset fehl. Wenn diese Funktionen erfolgreich einen Cursor erstellen, wenden sie eine exklusive Sperre für das Dataset an, sodass zwei Skripten keine Aktualisierung erstellen oder einen Cursor in dasselbe Dataset einfügen können.

In Python bleibt die Sperre bestehen, bis der Cursor freigegeben wird. Andernfalls könnte unnötigerweise verhindert werden, dass alle anderen Anwendungen oder Skripte auf einen Datensatz zugreifen. Ein Cursor kann durch eine der folgenden Aktionen ausgelöst werden:

Einfügen des Cursors in eine with-Anweisung, die das Aufheben von Sperren garantiert, unabhängig davon, ob der Cursor erfolgreich ausgeführt wurde oder nicht.

Aufruf von reset () am Cursor;

Die Vervollständigung des Cursors;

Explizites Löschen des Cursors mit der del-Anweisung von Python - ESRI

Das Sperren mit arcpy.da-Cursorn entspricht im Wesentlichen dem Sperren mit den ursprünglichen arcpy-Cursorn.

Nachdem Sie Ihren Code getestet haben und wie Gberard betont hat, gibt es nach dem Ende des Verständnisses keinen Verweis auf den Cursor.
Außerdem gibt es keine Sperren für die Feature-Class, nachdem das Verständnis beendet ist.

jbalk
quelle
1
Was löschen? Nach dem Ende des Verständnisses gibt es keinen Verweis auf das Cursorobjekt, daher sollte es theoretisch geschlossen werden. Ob sich die Implementierung von ESRI erwartungsgemäß verhält oder nicht, ist eine andere Frage, und ich denke, die Dokumente beantworten das nicht wirklich.
Mikewatt