Kapan del berguna dalam python?

374

Saya tidak dapat memikirkan alasan mengapa python membutuhkan delkata kunci (dan sebagian besar bahasa tampaknya tidak memiliki kata kunci yang serupa). Sebagai contoh, alih-alih menghapus variabel, seseorang bisa langsung menugaskannya None. Dan ketika menghapus dari kamus, sebuah delmetode dapat ditambahkan.

Apakah ada alasan untuk tetap delmenggunakan python, atau hanya sisa-sisa masa pengumpulan sampah sebelum Python?

Jason Baker
sumber
46
Catatan sejarah : Python memiliki pengumpulan sampah dari awal. Sebelum 2.0, pengumpul sampah Python tidak dapat mendeteksi siklus referensi, tapi itu tidak ada hubungannya dengan del.
Steven Rumbalski
28
@ Sebelas Rumbalksi, itu ada hubungannya dengan del. Del digunakan untuk memutus siklus referensi.
Winston Ewert
6
tetapi delbukan merupakan sisa pengumpulan sampah sebelum Anda dapat selalu melakukannya used = None. Itu selalu masuk akal untuk memiliki sintaks khusus untuk itu. Karena kami memiliki GC GC sekarang, kasus di mana Anda ingin menggunakan keduanya kecil.
Winston Ewert
3
> dan sebagian besar bahasa tampaknya tidak memiliki kata kunci yang mirip. Sebagian besar bahasa yang dikumpulkan sampah tidak (atau hanya menggunakannya untuk memberi petunjuk kepada GC bahwa ia dapat mengumpulkan variabel). Sebagian besar bahasa yang lebih tua: - Bahasa BASIC tua yang baik seperti QuickBasic telah ERASE(membunuh variabel tertentu) dan CLEAR(membunuh semua variabel)
DrYak

Jawaban:

499

Pertama, Anda dapat del hal-hal lain selain variabel lokal

del list_item[4]
del dictionary["alpha"]

Keduanya harus jelas bermanfaat. Kedua, menggunakan delvariabel lokal membuat maksud menjadi lebih jelas. Membandingkan:

del foo

untuk

foo = None

Saya tahu dalam kasus ini del footujuannya adalah untuk menghapus variabel dari ruang lingkup. Tidak jelas foo = Noneapakah melakukan itu. Jika seseorang baru saja ditugaskan foo = Nonesaya mungkin berpikir itu kode mati. Tapi saya langsung tahu apa yang seseorang del foocoba lakukan.

Winston Ewert
sumber
51
+1, ya. Saat Anda menetapkan sesuatu, itu menyampaikan maksud untuk menggunakannya nanti. Saya hanya benar-benar melihat deldigunakan dalam perhitungan intensif memori, tetapi ketika saya melihatnya saya segera menyadari mengapa itu perlu.
detly
17
Kasus penggunaan menghapus dari daftar atau kamus dapat dengan mudah diganti dengan metode (seperti yang saya catat dalam pertanyaan). Saya tidak yakin saya setuju dengan penggunaan deluntuk memberi sinyal niat (karena komentar dapat melakukan hal yang sama tanpa menambahkan bahasa), tapi saya kira itu jawaban terbaik.
Jason Baker
6
@JasonBaker, diberikan metode. Menghapus irisan dan semacamnya akan lebih canggung menggunakan metode. Ya, Anda bisa menggunakan komentar. Tapi saya pikir menggunakan pernyataan lebih baik daripada komentar sebagai bagian dari bahasanya.
Winston Ewert
2
@JasonBaker: Ini bukan hanya tentang niat, kedua sintaksis melakukan dua hal yang sangat berbeda.
Pavel Šimerda
2
Ini juga ditangani dengan menghapusnya dari kamus masing-masing. Anda juga dapat menyengketakan len()fungsi dengan cara yang sama. Jika ini masalahnya, pertanyaannya mungkin telah ditutup sebagai pendapat atau bahkan berdasarkan selera. Python cenderung memberikan primitif untuk operasi dasar daripada mengandalkan metode.
Pavel Šimerda
161

Ada bagian ini dari apa del(dari Python Language Reference ):

Penghapusan nama menghapus pengikatan nama itu dari namespace lokal atau global

Menetapkan Nonenama tidak menghapus pengikatan nama dari namespace.

(Saya kira mungkin ada beberapa perdebatan tentang apakah menghapus ikatan nama sebenarnya berguna , tapi itu pertanyaan lain.)

Greg Hewgill
sumber
22
-1 Poster jelas sudah memahami ini, dia bertanya mengapa Anda ingin menghapus nama yang mengikat.
Winston Ewert
71
@ Winston Ewert: Saya tidak yakin poster mengerti bahwa delmenghapus nama yang mengikat saat ia menyarankan untuk ditugaskan Nonesebagai alternatif.
Steven Rumbalski
8
@ Sebelas, poster dengan jelas kontras menghapus variabel (menghapus nama) dan menetapkan Tidak ada. Dia tidak melihat mengapa Anda harus menghapus variabel ketika Anda bisa menetapkan Tidak ada. Mereka memiliki efek yang sama ketika mereka merilis referensi ke apa pun yang sebelumnya terikat dengan nama itu.
Winston Ewert
19
@ Winston Ewert: Tidak jelas bagi saya. Mungkin jelas bagi Anda bahwa Anda menyatakan bahwa mereka "memiliki efek yang sama dalam melepaskan referensi ke apa pun yang sebelumnya terikat dengan nama itu." Tapi itu (jelas?) Bukan keseluruhan cerita dalam upaya untuk menggunakan nama setelah menghapusnya menimbulkan a NameError. Greg Hewgill membuat perbedaan ini. Dan perbedaan inilah yang membuat pernyataan Anda tentang apa yang "jelas" dipahami poster itu tidak jelas bagi saya.
Steven Rumbalski
9
@ Winston Ewert Saya tidak setuju. Tapi cukup kata. Kami berdua membuat kasus kami.
Steven Rumbalski
44

Satu tempat yang menurut saya delberguna adalah membersihkan variabel asing untuk loop:

for x in some_list:
  do(x)
del x

Sekarang Anda dapat yakin bahwa x akan tidak terdefinisi jika Anda menggunakannya di luar for for loop.

Jason Baker
sumber
1
Apakah delbaris Anda di sini seharusnya diberi indentasi (yaitu bagian dari loop)?
Sam
11
@ Sam, Tidak, mereka tidak dimaksudkan.
user5319825
7
@ Sam Tidak, idenya di sini adalah bahwa setelah iterasi terakhir dari loop (setelah melakukan do () pada elemen terakhir some_list), x akan tetap menjadi referensi ke nilai akhir some_list. del x memastikan ini tidak tetap ditugaskan seperti itu.
Matius
12
Ini akan menyebabkan NameError: name 'x' is not definedjika daftar kosong.
WofWca
18

Menghapus variabel berbeda dari mengaturnya ke Tidak ada

Menghapus nama variabel dengan delmungkin adalah sesuatu yang jarang digunakan, tetapi itu adalah sesuatu yang tidak dapat dicapai secara sepele tanpa kata kunci. Jika Anda dapat membuat nama variabel dengan menulis a=1, alangkah baiknya Anda secara teoritis dapat membatalkan ini dengan menghapus a.

Dalam beberapa kasus, proses debug bisa lebih mudah karena mencoba mengakses variabel yang dihapus akan meningkatkan NameError.

Anda dapat menghapus atribut instance kelas

Python memungkinkan Anda menulis sesuatu seperti:

class A(object):
    def set_a(self, a):
        self.a=a
a=A()
a.set_a(3)
if hasattr(a, "a"):
    print("Hallo")

Jika Anda memilih untuk menambahkan atribut secara dinamis ke instance kelas, Anda tentu ingin dapat membatalkannya dengan menulis

del a.a
Bernhard
sumber
16

Ada contoh spesifik kapan Anda harus menggunakan del(mungkin ada yang lain, tapi saya tahu tentang ini begitu saja) ketika Anda menggunakan sys.exc_info()untuk memeriksa pengecualian. Fungsi ini mengembalikan tupel, jenis pengecualian yang dimunculkan, pesan, dan traceback.

Dua nilai pertama biasanya cukup untuk mendiagnosis kesalahan dan menindaklanjutinya, tetapi yang ketiga berisi seluruh tumpukan panggilan antara tempat pengecualian dimunculkan dan di mana pengecualian ditangkap. Khususnya, jika Anda melakukan sesuatu seperti

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    if something(exc_value):
        raise

traceback, tbberakhir di penduduk setempat dari tumpukan panggilan, membuat referensi melingkar yang tidak dapat dikumpulkan sampah. Dengan demikian, penting untuk dilakukan:

try:
    do_evil()
except:
    exc_type, exc_value, tb = sys.exc_info()
    del tb
    if something(exc_value):
        raise

untuk mematahkan referensi melingkar. Dalam banyak kasus di mana Anda ingin memanggil sys.exc_info(), seperti dengan sihir metaclass, traceback yang adalah berguna, sehingga Anda harus memastikan bahwa Anda membersihkannya sebelum Anda mungkin dapat meninggalkan handler pengecualian. Jika Anda tidak memerlukan traceback, Anda harus segera menghapusnya, atau cukup lakukan:

exc_type, exc_value = sys.exc_info()[:2]

Untuk menghindarinya bersama-sama.

SingleNegationElimination
sumber
18
Tidak lagi benar bahwa pengumpul sampah tidak akan mengumpulkannya. Namun, siklus akan menunda pengumpulan.
Winston Ewert
Ini tidak terlalu relevan, dan tidak menjawab pertanyaan op.
WhyNotHugo
15

Hanya pemikiran lain.

Ketika men-debug aplikasi http dalam kerangka kerja seperti Django, tumpukan panggilan penuh variabel yang tidak berguna dan kacau yang sebelumnya digunakan, terutama ketika itu adalah daftar yang sangat panjang, bisa sangat menyakitkan bagi pengembang. jadi, pada titik ini, mengendalikan namespace bisa bermanfaat.

tdihp
sumber
12

Menggunakan "del" secara eksplisit juga merupakan praktik yang lebih baik daripada menugaskan variabel ke Tidak ada. Jika Anda mencoba untuk del variabel yang tidak ada, Anda akan mendapatkan kesalahan runtime tetapi jika Anda mencoba untuk mengatur variabel yang tidak ada ke None, Python akan secara diam-diam mengatur variabel baru ke None, meninggalkan variabel yang Anda ingin dihapus di tempat itu. Jadi del akan membantu Anda menangkap kesalahan Anda sebelumnya

Mat
sumber
11

Untuk menambahkan beberapa poin ke jawaban di atas: del x

Definisi xmenunjukkan r -> o(referensi rmenunjuk ke suatu objek o) tetapi del xberubah rdaripada o. Ini adalah operasi pada referensi (pointer) ke objek daripada objek yang terkait dengannya x. Membedakan antara rdan omerupakan kunci di sini.

  • Itu menghapusnya dari locals().
  • Menghapusnya globals()jika xada di sana.
  • Menghapusnya dari bingkai tumpukan (menghapus referensi secara fisik dari itu, tetapi objek itu sendiri berada di kumpulan objek dan bukan di bingkai tumpukan).
  • Menghapusnya dari ruang lingkup saat ini. Sangat berguna untuk membatasi rentang definisi variabel lokal, yang jika tidak dapat menyebabkan masalah.
  • Ini lebih tentang deklarasi nama daripada definisi konten.
  • Ini mempengaruhi tempat xmilik, bukan tempat xmenunjuk. Satu-satunya perubahan fisik dalam ingatan adalah ini. Misalnya jika xada dalam kamus atau daftar, itu (sebagai referensi) dihapus dari sana (dan tidak harus dari kumpulan objek). Dalam contoh ini, kamus yang dimilikinya adalah bingkai tumpukan ( locals()), yang tumpang tindih dengan globals().
Sohail Si
sumber
6

Paksa menutup file setelah menggunakan numpy.load:

Penggunaan niche mungkin tapi saya merasa berguna saat menggunakan numpy.loaduntuk membaca file. Sesekali saya akan memperbarui file dan perlu menyalin file dengan nama yang sama ke direktori.

Saya biasa delmelepaskan file dan mengizinkan saya untuk menyalin di file baru.

Catatan Saya ingin menghindari withmanajer konteks karena saya bermain-main dengan plot pada baris perintah dan tidak ingin banyak menekan tab!

Lihat pertanyaan ini .

atomh33ls
sumber
Saya memiliki sesuatu yang mirip dengan Gambar yang dimuat dengan Python Image Library (PIL). Saya membuka gambar, dan jika memiliki dimensi tertentu, saya ingin menghapus file; namun file tersebut masih digunakan oleh Python. Karena itu, saya katakan 'del img', dan kemudian bisa menghapus file.
physicalattraction
2
Hati-hati bahwa ini adalah detail implementasi karena spesifikasi bahasa tidak menjamin ketika __del__()metode pada objek sampah dipanggil atau bahkan jika dipanggil sama sekali. Jadi API yang tidak menawarkan cara untuk melepaskan sumber daya selain berharap __del__()metode dipanggil beberapa saat (segera setelah objeknya sampah) rusak sampai batas tertentu.
BlackJack
6

delsering terlihat dalam __init__.pyfile. Setiap variabel global yang didefinisikan dalam suatu __init__.pyfile secara otomatis "diekspor" (akan dimasukkan dalam a from module import *). Salah satu cara untuk menghindari ini adalah dengan mendefinisikan __all__, tetapi ini bisa berantakan dan tidak semua orang menggunakannya.

Misalnya, jika Anda memiliki kode __init__.pysuka

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

Maka modul Anda akan mengekspor sysnama. Anda sebaiknya menulis

import sys
if sys.version_info < (3,):
    print("Python 2 not supported")

del sys
penilai
sumber
4

Sebagai contoh dari apa yang deldapat digunakan untuk, saya merasa berguna dalam situasi seperti ini:

def f(a, b, c=3):
    return '{} {} {}'.format(a, b, c)

def g(**kwargs):
    if 'c' in kwargs and kwargs['c'] is None:
        del kwargs['c']

    return f(**kwargs)

# g(a=1, b=2, c=None) === '1 2 3'
# g(a=1, b=2) === '1 2 3'
# g(a=1, b=2, c=4) === '1 2 4'

Kedua fungsi dapat di berbagai paket / modul dan programmer tidak perlu tahu apa nilai default argumen cdi fbenar-benar memiliki. Jadi dengan menggunakan kwarg dalam kombinasi dengan del Anda dapat mengatakan "Saya ingin nilai default pada c" dengan mengaturnya ke None (atau dalam hal ini juga biarkan).

Anda dapat melakukan hal yang sama dengan sesuatu seperti:

def g(a, b, c=None):
    kwargs = {'a': a,
              'b': b}
    if c is not None:
        kwargs['c'] = c

    return f(**kwargs)

Namun saya menemukan contoh sebelumnya lebih KERING dan elegan.

Jocke
sumber
3

Kapan del berguna dalam python?

Anda dapat menggunakannya untuk menghapus satu elemen array bukan sintaks slice x[i:i+1]=[]. Ini mungkin berguna jika misalnya Anda berada di os.walkdan ingin menghapus elemen dalam direktori. Saya tidak akan menganggap kata kunci berguna untuk ini, karena orang hanya bisa membuat [].remove(index)metode ( .removemetode ini sebenarnya mencari-dan-hapus-contoh-nilai-pertama).

ninjagecko
sumber
7
[].pop(index)dan [].remove(item). Jangan gunakan variabel bernama "index"ketika berbicara tentang nilai, membuatnya terlihat membingungkan.
Ski
@ Pop pop tidak menggunakan indeks . Ini adalah jawaban yang valid sedangkan setengah dari jawaban ini hanya memberikan contoh menggunakan del di mana Tidak ada juga akan bekerja. Objek daftar yang diatur ke Tidak ada masih ada dalam daftar sedangkan del menghapus item.
user5389726598465
3

Saya menemukan delberguna untuk manajemen memori pseudo-manual ketika menangani data besar dengan Numpy. Sebagai contoh:

for image_name in large_image_set:
    large_image = io.imread(image_name)
    height, width, depth = large_image.shape
    large_mask = np.all(large_image == <some_condition>)
    # Clear memory, make space
    del large_image; gc.collect()

    large_processed_image = np.zeros((height, width, depth))
    large_processed_image[large_mask] = (new_value)
    io.imsave("processed_image.png", large_processed_image)

    # Clear memory, make space
    del large_mask, large_processed_image; gc.collect()

Ini bisa menjadi perbedaan antara membawa skrip terhenti saat sistem bertukar sangat gila ketika Python GC tidak dapat mengimbangi, dan itu berjalan sangat halus di bawah ambang memori yang longgar yang membuat banyak ruang kepala menggunakan mesin untuk menelusuri dan kode saat sedang bekerja.

Saraf
sumber
2

Saya pikir salah satu alasan bahwa del memiliki sintaks sendiri adalah bahwa menggantinya dengan fungsi mungkin sulit dalam kasus-kasus tertentu mengingat beroperasi pada pengikatan atau variabel dan bukan nilai referensi itu. Jadi, jika versi fungsi del dibuat konteks perlu dilewati. Del foo perlu menjadi global (). Remove ('foo') atau lokal (). Remove ('foo') yang menjadi berantakan dan kurang bisa dibaca. Masih saya katakan menyingkirkan del akan baik mengingat penggunaannya yang tampaknya jarang. Tetapi menghapus fitur / kekurangan bahasa bisa menyakitkan. Mungkin python 4 akan menghapusnya :)

wafel-kabur
sumber
2

Saya ingin menguraikan jawaban yang diterima untuk menyoroti nuansa antara menetapkan variabel Nonedibandingkan menghapusnya dengan del:

Diberikan variabel foo = 'bar', dan definisi fungsi berikut:

def test_var(var):
    if var:
        print('variable tested true')
    else:
        print('variable tested false')

Setelah awalnya dinyatakan, test_var(foo)hasil variable tested trueseperti yang diharapkan.

Sekarang coba:

foo = None
test_var(foo)

yang menghasilkan variable tested false.

Bandingkan perilaku ini dengan:

del foo
test_var(foo)

yang sekarang memunculkan NameError: name 'foo' is not defined.

Jacobs
sumber
0

Namun penggunaan niche lainnya: Di pyroot dengan ROOT5 atau ROOT6, "del" mungkin berguna untuk menghapus objek python yang merujuk ke objek C ++ yang sudah tidak ada lagi. Ini memungkinkan pencarian dinamis dari pyroot untuk menemukan objek C ++ yang identik dinamai dan mengikatnya ke nama python. Jadi Anda dapat memiliki skenario seperti:

import ROOT as R
input_file = R.TFile('inputs/___my_file_name___.root')
tree = input_file.Get('r')
tree.Draw('hy>>hh(10,0,5)')
R.gPad.Close()
R.hy # shows that hy is still available. It can even be redrawn at this stage.
tree.Draw('hy>>hh(3,0,3)') # overwrites the C++ object in ROOT's namespace
R.hy # shows that R.hy is None, since the C++ object it pointed to is gone
del R.hy
R.hy # now finds the new C++ object

Semoga ceruk ini akan ditutup dengan manajemen objek ROOT7 yang lebih waras.

Amnon Harel
sumber
0

Perintah "del" sangat berguna untuk mengendalikan data dalam array, misalnya:

elements = ["A", "B", "C", "D"]
# Remove first element.
del elements[:1]
print(elements)

Keluaran:

['B', 'C', 'D']

Victor Marrerp
sumber
-2

Pernah saya harus menggunakan:

del serial
serial = None

karena hanya menggunakan:

serial = None

tidak merilis port serial dengan cukup cepat untuk segera membukanya lagi. Dari pelajaran yang saya pelajari itu delbenar - benar berarti: "GC SEKARANG! Dan tunggu sampai selesai" dan itu benar-benar berguna dalam banyak situasi. Tentu saja, Anda mungkin punya system.gc.del_this_and_wait_balbalbalba(obj).

alfredolavin
sumber
5
Hmm ... Itu seharusnya tidak membuat perbedaan. Meskipun, mungkin masalah Anda telah diperbaiki oleh penundaan tambahan yang diperkenalkannya?
Winston Ewert
3
Saya tidak berpikir Anda dapat mendukung GC ini sekarang dengan dokumentasi apa pun. Saya pikir mengandalkan GC dan menelepon ke __del__()selalu salah dengan Python (saya tidak tahu alasan untuk desain ini, meskipun) dan lebih baik menggunakan konteks manager API ( withpernyataan).
Pavel Šimerda
1
Itu semacam pemrograman voodoo. Lihat deskripsi metode dan catatan dalam dokumentasi untuk objek .__ del __ () untuk detailnya, dan perlu diingat ini hanya menjelaskan implementasi CPythons saat ini dengan penghitungan referensi. Implementasi Python lainnya (PyPy, Jython, IronPython, Brython, ...) atau implementasi CPython di masa depan dapat menggunakan skema pengumpulan sampah yang berbeda. Jython menggunakan JVMs GC yang tidak langsung menghapus objek. The serialModul juga bekerja dengan Jython sehingga Anda hack tidak bekerja di sana!
BlackJack
BTW gc.collect akan menjadi cara untuk mendaur ulang secara eksplisit. Didukung di sebagian besar implementasi python.
tdihp
-2

del adalah setara dengan "tidak disetel" dalam banyak bahasa dan sebagai titik referensi silang pindah dari bahasa lain ke python .. orang cenderung mencari perintah yang melakukan hal yang sama seperti dulu dalam bahasa pertama mereka ... juga mengatur var ke "" atau tidak ada yang tidak benar-benar menghapus var dari scope..it hanya mengosongkan nilainya nama var itu sendiri masih akan disimpan dalam memori ... mengapa?!? dalam skrip memori intensif..membersihkan sampah di belakangnya hanya no no dan anyways ... setiap bahasa di luar sana memiliki beberapa bentuk fungsi var "unset / delete" .. mengapa tidak python?

Francisco
sumber
7
deltidak meminta pengumpul sampah lebih cepat daripada = None, juga tidak akan meninggalkan sampah dalam jangka panjang. Anda mungkin ingin mendapatkan koleksi sampah Python.
SilverbackNet
-3

Setiap objek dalam python memiliki pengidentifikasi, tipe, jumlah referensi yang terkait dengannya, ketika kita menggunakan del jumlah referensi berkurang, ketika jumlah referensi menjadi nol itu adalah kandidat potensial untuk mengumpulkan sampah. Ini membedakan del bila dibandingkan dengan menetapkan pengidentifikasi ke Tidak ada. Dalam kasus selanjutnya, itu berarti objek dibiarkan liar (sampai kita berada di luar ruang lingkup dalam hal ini jumlah berkurang) dan sekarang pengidentifikasi menunjuk ke beberapa objek lain (lokasi memori).

SaiReddy
sumber
3
Saya ingin melihat buktinya. Menetapkan Tidak ada yang harus mengurangi jumlah referensi.
Jason Baker
3
Ini omong kosong dan kebalikan dari pengumpulan sampah (dalam arti meninggalkan sampah di sekitar).
Pavel Šimerda