Eliminazione del cursore utilizzato in SearchCursor nella comprensione del dizionario?


12

Se è meglio aprire i cursori utilizzando un'istruzione with per assicurarsi che venga eliminata, in questo modo:

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

Quindi, se un cursore viene utilizzato come iterabile in una comprensione del genere:

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

È necessario eliminare il cursore dopo averlo usato nella comprensione?


1
Ottima domanda Stai cercando di gestire i blocchi dello schema? Ci sono alcuni primi post (per lo più obsoleti) su un argomento simile, anche se non riesco a trovare una fonte definitiva sui nuovi dacursori: sgillies.net/2011/02/01/get-with-it.html e help.arcgis.com/ it / arcgisdesktop / 10.0 / help / index.html # //… . In particolare, guarda i commenti di @JasonScheirer nella parte inferiore del primo link.
Aaron

Risposte:


13

Se è assolutamente necessario è la domanda sbagliata da porre. La domanda è se è una buona idea.

Come regola di programmazione, dovresti evitare di fare cose strane e utilizzare lo strumento migliore per il lavoro . Se qualcosa ha un modo esplicito di rilasciare risorse, basta rendere esplicito il rilascio e completare l'operazione:

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

Ciò di cui potresti non essere a conoscenza è che la withclausola invoca effettivamente una logica aggiuntiva. Una withclausola richiede un gestore di contesto, che deve avere un metodo __enter__(invocato quando viene inserito il blocco) e __exit__(invocato quando si esce dal blocco). In particolare, il __exit__metodo viene invocato indipendentemente dal fatto che si sia verificata un'eccezione, assicurando che il programma rilasci sempre la risorsa anche in caso di errore. Ciò fornisce al tuo codice la documentazione esplicita di quando viene acquisita una risorsa e quando viene rilasciata e garantisce che una risorsa possa essere rilasciata il più presto possibile.

Al contrario, in realtà non puoi dipendere dal runtime per chiuderlo magicamente immediatamente per te. Questo perché il modo in cui viene chiuso è invocando il distruttore dell'oggetto, che può accadere o meno immediatamente. Python non fornisce alcuna garanzia su quando viene invocato un distruttore, solo che lo sarà alla fine quando l'oggetto viene raccolto. (Vedi qui .) Attualmente, Python è implementato in modo tale che accada non appena non c'è più un riferimento a un oggetto. Ma è facile propagare accidentalmente i riferimenti a un oggetto e il runtime di Python potrebbe cambiare.

Considera anche la manutenzione a lungo termine. Non ci sono riferimenti a lungo termine ora, ma cosa succede in 6 mesi quando è necessario modificare il codice in modo che ci sia un riferimento? E se lo facesse qualcun altro? La persona che apporta la modifica potrebbe non pensare di passare a un withblocco poiché non ce n'è già uno lì. Trasforma le tue risorse in un'abitudine e avrai molti meno problemi.

Vuoi davvero legare il tuo codice ai dettagli di implementazione della garbage collection? Vuoi pensare costantemente se potresti propagare accidentalmente un riferimento tramite un'eccezione? No, non lo fai. Immagina se ciò accadesse quando lo script è stato invocato in ArcMap. L'utente sarebbe costretto a chiudere l'intero processo solo per rilasciare il file. Quindi non metterti in quella posizione. Rilasciare la risorsa esplicitamente. Salvare una riga di codice non vale i rischi di problemi che può causare. I gestori di contesto sono il meccanismo standard per l'acquisizione e il rilascio di risorse in Python e lo fanno molto bene.

La linea di fondo è che non rilasciarlo esplicitamente è una cattiva idea.

Questo, ovviamente, presuppone che il codice abbia qualche possibilità di influenzare qualcun altro, come inserirlo in uno script che qualcun altro dovrà eseguire o mantenere o potrebbe ritardare la consegna del tuo lavoro se devi chiudere ArcMap fino in fondo perché impossibile salvare le modifiche. Se sei l'unico a essere colpito da un problema, allora vola di fronte alle buone pratiche tutto ciò che desideri.


3

No, non è necessario eliminare un cursordopo averlo usato in una comprensione. A cursorè un'istanza di una classe, che è un oggetto (tutto in Python è un oggetto). Ogni sessione di Python ha una namespaceche contiene riferimenti a tutti gli oggetti nella sessione: pensala come un dizionario in cui le chiavi sono riferimenti a ciascun oggetto e i valori sono gli oggetti stessi. Quando il "conteggio dei riferimenti" - il numero di chiavi che fanno riferimento a quell'oggetto - scende a zero, l'oggetto viene rimosso e la memoria viene riassegnata . Quando usi a cursorin una comprensione, non c'è alcun riferimento a quell'oggetto nello spazio dei nomi. Al termine della comprensione, l'oggetto verrà eliminato.

Non vi è alcuna voce nello spazio dei nomi e quindi non è necessario eliminare nulla. ESRI illustra anche questa sintassi nell'esempio 2, qui .

Per chiarire ulteriormente, se si esegue:

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

Vedrai apparire un file .lock nella directory (controlla il tuo esploratore di file). Il riferimento al cursore è a, che farà cursorpersistere (e quindi il blocco) fino a quando non aviene eliminato. Quindi quando corri:

>>> del(a)

La voce nello spazio dei nomi verrà rimossa e il blocco verrà rilasciato (il file .lock scomparirà). Se corri:

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

O non vedrai un file di blocco o scomparirà quando il comando sarà completato. Senza una voce nello spazio dei nomi, cursornon è persistente. tsi riferisce all'elenco appena creato, non a quello cursorutilizzato per crearlo.

Per riassumere, devi solo preoccuparti di eliminare cursorsquando hanno un riferimento nello spazio dei nomi (cioè quando li hai assegnati a una variabile, come anell'esempio sopra).


2
Questa è una pratica di programmazione estremamente scadente. Se qualcosa ha un modo esplicito di rilasciare risorse, lo usi .
jpmc26,

@ jpmc26, Quale parte è "pratica di programmazione estremamente scadente"? Comprensioni in generale? O solo se l'iterabile è istanziato nella comprensione? Ho pensato che un argomento forte per quest'ultimo è che rilascia immediatamente la risorsa.
Tom,

@ Tom Non rilasciare risorse esplicitamente. Le comprensioni sono strumenti fantastici e creare un'istanza di normali iterabili al loro interno è del tutto normale. Ciò che è male qui è che gli oggetti cursore acquisiscono blocchi di file e non esiste un rilascio esplicito di essi. Vedi la mia risposta per maggiori dettagli.
jpmc26,

2

I cursori di aggiornamento e inserimento non possono essere creati per una tabella o una classe di funzionalità se esiste un blocco esclusivo per quel set di dati. Le funzioni UpdateCursor o InsertCursor hanno esito negativo a causa di un blocco esclusivo sul set di dati. Se queste funzioni creano correttamente un cursore, applicano un blocco esclusivo sul set di dati in modo che due script non possano creare un aggiornamento o inserire il cursore sullo stesso set di dati.

In Python, il blocco persiste fino a quando il cursore non viene rilasciato. Altrimenti, a tutte le altre applicazioni o script potrebbe essere inutilmente impedito l'accesso a un set di dati. Un cursore può essere rilasciato da uno dei seguenti:

Incluso il cursore all'interno di un'istruzione with, che garantirà il rilascio dei blocchi indipendentemente dal completamento corretto del cursore;

Richiamo di reset () sul cursore;

Il completamento del cursore;

Eliminazione esplicita del cursore usando l'istruzione del di Python - ESRI

Il blocco con i cursori arcpy.da è praticamente lo stesso del blocco con i cursori arcpy originali.

Dopo aver testato il tuo codice, e come ha sottolineato gberard, non c'è alcun riferimento al cursore dopo che la comprensione termina.
Inoltre, non ci sono blocchi sulla classe di funzionalità al termine della comprensione.


1
Cancellare cosa? Non c'è alcun riferimento all'oggetto cursore dopo la fine della comprensione, quindi in teoria dovrebbe chiudersi. Se l'implementazione dell'ESRI si comporti come ci si aspetterebbe è un'altra domanda, e non credo che i documenti rispondano davvero.
mikewatt,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.