Menghapus kursor yang digunakan dalam SearchCursor dalam pemahaman kamus?

12

Jika yang terbaik adalah membuka kursor menggunakan pernyataan with untuk memastikan itu dihapus, seperti:

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

Kemudian, jika kursor digunakan sebagai iterable dalam pemahaman seperti:

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

Apakah perlu untuk menghapus kursor setelah menggunakannya dalam pemahaman?

J. Flann
sumber
1
Pertanyaan yang bagus Apakah Anda mencoba menangani kunci skema? Ada beberapa posting awal (kebanyakan kedaluwarsa) pada topik yang sama, meskipun saya tidak dapat menemukan sumber definitif pada dakursor baru : sgillies.net/2011/02/01/get-with-it.html dan help.arcgis.com/ id / arcgisdesktop / 10.0 / help / index.html # //… . Secara khusus, lihat komentar @JasonScheirer di bagian bawah tautan pertama.
Aaron

Jawaban:

13

Apakah itu mutlak diperlukan adalah pertanyaan yang salah untuk ditanyakan. Pertanyaannya adalah apakah itu ide yang bagus.

Sebagai aturan dalam pemrograman, Anda harus menghindari melakukan hal-hal aneh dan menggunakan alat terbaik untuk pekerjaan itu . Jika sesuatu memiliki cara eksplisit untuk melepaskan sumber daya, cukup buat rilis itu eksplisit dan lakukan dengan itu:

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

Apa yang mungkin tidak Anda sadari adalah bahwa withklausa sebenarnya memunculkan logika tambahan. Sebuah withklausul membutuhkan manajer konteks, yang harus memiliki __enter__(dipanggil saat blok dimasukkan) dan __exit__(dipanggil saat blok tersebut keluar) metode. Secara khusus, __exit__metode ini dipanggil terlepas dari apakah pengecualian terjadi, memastikan program selalu melepaskan sumber daya meskipun ada kesalahan. Ini memberikan kode Anda dokumentasi eksplisit tentang kapan sumber daya diperoleh dan kapan dirilis, dan memastikan bahwa sumber daya dapat dirilis sesegera mungkin.

Sebaliknya, Anda tidak dapat benar-benar bergantung pada runtime untuk segera menutupnya secara ajaib untuk Anda. Ini karena cara itu ditutup adalah dengan memanggil destruktor objek, yang mungkin atau mungkin tidak terjadi segera. Python tidak membuat jaminan tentang kapan sebuah destructor dipanggil, hanya saja pada akhirnya ketika objek tersebut adalah sampah yang dikumpulkan. (Lihat di sini .) Saat ini, Python diimplementasikan sehingga terjadi segera setelah tidak ada lagi referensi ke objek. Tetapi mudah untuk secara tidak sengaja menyebarkan referensi ke suatu objek, dan runtime Python mungkin berubah.

Juga pertimbangkan perawatan jangka panjang. Tidak ada referensi jangka panjang untuk sekarang, tetapi apa yang terjadi di 6 bulan ketika Anda perlu memodifikasi kode sehingga ada adalah referensi? Bagaimana jika orang lain melakukannya? Orang yang membuat perubahan mungkin tidak berpikir untuk beralih ke withblok karena tidak ada yang sudah ada di sana. Membuat membersihkan sumber daya Anda kebiasaan , dan Anda akan memiliki lebih sedikit masalah dengan itu.

Apakah Anda benar-benar ingin mengikat kode Anda ke detail implementasi pengumpulan sampah? Apakah Anda ingin terus-menerus memikirkan apakah Anda mungkin secara tidak sengaja menyebarkan referensi melalui pengecualian? Tidak, tidak. Bayangkan jika itu terjadi ketika skrip dipanggil di ArcMap. Pengguna akan dipaksa untuk menutup seluruh proses hanya untuk melepaskan file. Jadi jangan menempatkan diri Anda pada posisi itu. Lepaskan sumber daya secara eksplisit. Menyimpan satu baris kode tidak sebanding dengan risiko masalah yang diakibatkannya. Manajer konteks adalah mekanisme standar untuk memperoleh dan melepaskan sumber daya dengan Python, dan mereka melakukannya dengan sangat baik.

Intinya adalah bahwa tidak merilisnya secara eksplisit adalah ide yang buruk.

Ini, tentu saja, mengasumsikan bahwa kode tersebut memiliki kemungkinan mempengaruhi orang lain, seperti memasukkannya ke dalam skrip yang harus dijalankan atau dikelola orang lain atau mungkin menunda penyerahan pekerjaan Anda jika Anda harus menutup ArcMap sepenuhnya karena Anda tidak dapat menyimpan perubahan Anda. Jika Anda satu-satunya yang akan terkena dampak masalah, maka dengan segala cara, terbanglah di hadapan praktik-praktik baik yang Anda inginkan.

jpmc26
sumber
3

Tidak, tidak perlu menghapus cursorsetelah menggunakannya dalam pemahaman. A cursoradalah turunan dari kelas, yang merupakan objek (semua yang ada di python adalah objek). Setiap sesi python memiliki namespaceyang berisi referensi ke semua objek dalam sesi - anggap saja seperti kamus di mana kunci adalah referensi untuk setiap objek, dan nilainya adalah objek itu sendiri. Ketika 'jumlah referensi' - jumlah kunci yang merujuk ke objek itu - turun ke nol, objek dihapus dan memori dialokasikan kembali . Saat Anda menggunakan cursordalam pemahaman, tidak ada referensi ke objek di namespace. Setelah pemahaman selesai, objek akan dihapus.

Tidak ada entri di namespace, dan karenanya tidak perlu menghapus apa pun. ESRI juga menggambarkan sintaks ini dalam contoh 2, di sini .

Untuk lebih memperjelas, jika Anda menjalankan:

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

Anda akan melihat file .lock muncul di direktori (periksa file explorer Anda). Referensi kursor adalah a, yang akan membuat cursor(dan karena itu kunci) bertahan hingga adihapus. Jadi saat Anda menjalankan:

>>> del(a)

Entri di namespace akan dihapus, dan kunci akan dirilis (file .lock akan hilang). Jika Anda menjalankan:

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

Anda juga tidak akan melihat file kunci, atau itu akan hilang ketika perintah selesai. Tanpa entri di namespace, cursortidak persisten. tmerujuk ke daftar yang baru saja Anda buat, bukan yang cursordigunakan untuk membuatnya.

Untuk meringkas, Anda hanya perlu khawatir tentang menghapus cursorsketika mereka memiliki referensi di namespace (yaitu ketika Anda telah menetapkan mereka ke variabel, seperti apada contoh di atas).

Chris
sumber
2
Ini adalah praktik pemrograman yang sangat buruk. Jika ada sesuatu yang secara eksplisit melepaskan sumber daya, Anda menggunakannya .
jpmc26
@ jpmc26, Bagian mana yang merupakan "praktik pemrograman yang sangat buruk"? Pemahaman secara umum? Atau hanya jika iterable dipakai dalam pemahaman? Saya berpikir bahwa satu argumen kuat untuk yang terakhir adalah bahwa ia segera melepaskan sumber daya.
Tom
@ Tom Tidak merilis sumber daya secara eksplisit. Pemahaman adalah alat yang fantastis, dan instantiate iterables normal di dalamnya benar-benar normal. Apa yang buruk di sini adalah bahwa objek kursor mendapatkan kunci file dan tidak ada rilis eksplisit dari mereka. Lihat jawaban saya untuk lebih detail.
jpmc26
2

Perbarui dan masukkan kursor tidak dapat dibuat untuk tabel atau kelas fitur jika ada kunci eksklusif untuk dataset tersebut. Fungsi UpdateCursor atau InsertCursor gagal karena kunci eksklusif pada dataset. Jika fungsi-fungsi ini berhasil membuat kursor, mereka menerapkan kunci eksklusif pada dataset sehingga dua skrip tidak dapat membuat pembaruan atau menyisipkan kursor pada dataset yang sama.

Dalam Python, kunci tetap berlanjut sampai kursor dilepaskan. Jika tidak, semua aplikasi atau skrip lain dapat secara tidak perlu dicegah mengakses dataset. Kursor dapat dirilis oleh salah satu dari yang berikut:

Termasuk kursor di dalam pernyataan with, yang akan menjamin pelepasan kunci terlepas dari apakah kursor berhasil diselesaikan atau tidak;

Atur ulang panggilan () pada kursor;

Penyelesaian kursor;

Menghapus kursor secara eksplisit menggunakan pernyataan del Python - ESRI

Mengunci dengan kursor arcpy.da hampir sama dengan mengunci dengan kursor arcpy asli.

Setelah menguji kode Anda, dan seperti yang ditunjukkan gberard, tidak ada referensi ke kursor setelah pemahaman berakhir.
Juga, tidak ada kunci pada kelas fitur setelah pemahaman berakhir.

jbalk
sumber
1
Menghapus apa? Tidak ada referensi ke objek kursor setelah pemahaman berakhir, jadi secara teori itu harus ditutup. Apakah implementasi ESRI sesuai atau tidak seperti yang Anda harapkan adalah pertanyaan lain, dan saya pikir dokumen tidak benar-benar menjawabnya.
mikewatt