Perbedaan antara dict.clear () dan menetapkan {} dengan Python

167

Dalam python, apakah ada perbedaan antara memanggil clear()dan menugaskan {}ke kamus? Jika ya, apa itu? Contoh:

d = {"stuff":"things"}
d.clear()   #this way
d = {}      #vs this way

Marcin
sumber
Saya ingin tahu apakah ini membuat perbedaan pada bagian pengumpulan sampah. Saya merasa seperti .clear () harus lebih bagus untuk sistem memori.
Xavier Nicollet

Jawaban:

285

Jika Anda memiliki variabel lain yang juga merujuk ke kamus yang sama, ada perbedaan besar:

>>> d = {"stuff": "things"}
>>> d2 = d
>>> d = {}
>>> d2
{'stuff': 'things'}
>>> d = {"stuff": "things"}
>>> d2 = d
>>> d.clear()
>>> d2
{}

Ini karena penugasan d = {}membuat kamus baru yang kosong dan menugaskannya ke dvariabel. Ini meninggalkan d2menunjuk ke kamus lama dengan item masih di dalamnya. Namun, d.clear()membersihkan kamus yang sama yang ddan d2kedua titik di.

Greg Hewgill
sumber
7
Terima kasih. Ini masuk akal. Saya masih harus terbiasa dengan pola pikir yang = menciptakan referensi dengan python ...
Marcin
15
= menyalin referensi ke nama. Tidak ada variabel dalam python, hanya objek dan nama.
tzot
17
Meskipun pernyataan "tidak ada variabel" Anda benar, itu tidak terlalu membantu di sini. Selama dokumentasi bahasa Python masih berbicara tentang "variabel", saya masih akan menggunakan istilah: docs.python.org/reference/datamodel.html
Greg Hewgill
9
Saya menemukan komentar tzot membantu dalam menyesuaikan pemikiran saya tentang nama, variabel, dan jenis salinan. Menyebutnya bertele-tele mungkin pendapat Anda, tapi menurut saya itu penilaian yang kasar dan tidak adil.
cfwschmidt
1
Juga jelas () jangan hancurkan objek yang dihapus di dikt yang masih dapat dirujuk oleh orang lain.
Lorenzo Belli
31

d = {}akan membuat contoh baru untuk dtetapi semua referensi lain masih akan menunjuk ke konten lama. d.clear()akan mengatur ulang konten, tetapi semua referensi ke instance yang sama akan tetap benar.

Michel
sumber
21

Selain perbedaan yang disebutkan dalam jawaban lain, ada juga perbedaan kecepatan. d = {} selesai dua kali lebih cepat:

python -m timeit -s "d = {}" "for i in xrange(500000): d.clear()"
10 loops, best of 3: 127 msec per loop

python -m timeit -s "d = {}" "for i in xrange(500000): d = {}"
10 loops, best of 3: 53.6 msec per loop
odano
sumber
9
Ini sebenarnya bukan tes kecepatan yang valid untuk semua kasus karena dict kosong. Saya pikir membuat dikte besar (atau setidaknya beberapa konten) akan menghasilkan perbedaan kinerja yang jauh lebih kecil ... ditambah saya curiga pengumpul sampah mungkin menambahkan sedikit kerusakan sendiri ke d = {} (?)
Rafe
3
@Rafe: Saya pikir intinya adalah jika kita tahu bahwa tidak ada variabel lain yang menunjuk ke kamus d, maka pengaturan d = {}harus lebih cepat karena pembersihan keseluruhan dapat diserahkan kepada Pengumpul Sampah untuk nanti.
ViFI
8

Sebagai ilustrasi untuk hal-hal yang telah disebutkan sebelumnya:

>>> a = {1:2}
>>> id(a)
3073677212L
>>> a.clear()
>>> id(a)
3073677212L
>>> a = {}
>>> id(a)
3073675716L
maks
sumber
Ini menunjukkan bahwa .clearmemodifikasi objek tetapi `= {}` membuat objek baru.
wizzwizz4
7

Selain jawaban @odano, sepertinya menggunakan d.clear()lebih cepat jika Anda ingin menghapus dikt berkali-kali.

import timeit

p1 = ''' 
d = {}
for i in xrange(1000):
    d[i] = i * i
for j in xrange(100):
    d = {}
    for i in xrange(1000):
        d[i] = i * i
'''

p2 = ''' 
d = {}
for i in xrange(1000):
    d[i] = i * i
for j in xrange(100):
    d.clear()
    for i in xrange(1000):
        d[i] = i * i
'''

print timeit.timeit(p1, number=1000)
print timeit.timeit(p2, number=1000)

Hasilnya adalah:

20.0367929935
19.6444659233
lastland
sumber
4
Saya tidak yakin perbedaannya signifikan. Bagaimanapun, di mesin saya, hasilnya berlawanan!
Aristide
7

Metode bermutasi selalu berguna jika objek asli tidak dalam cakupan:

def fun(d):
    d.clear()
    d["b"] = 2

d={"a": 2}
fun(d)
d          # {'b': 2}

Menetapkan kembali kamus akan membuat objek baru dan tidak akan memodifikasi yang asli.

Karoly Horvath
sumber
4

Satu hal yang tidak disebutkan adalah masalah pelingkupan. Bukan contoh yang bagus, tapi inilah kasus di mana saya mengalami masalah:

def conf_decorator(dec):
    """Enables behavior like this:
        @threaded
        def f(): ...

        or

        @threaded(thread=KThread)
        def f(): ...

        (assuming threaded is wrapped with this function.)
        Sends any accumulated kwargs to threaded.
        """
    c_kwargs = {}
    @wraps(dec)
    def wrapped(f=None, **kwargs):
        if f:
            r = dec(f, **c_kwargs)
            c_kwargs = {}
            return r
        else:
            c_kwargs.update(kwargs) #<- UnboundLocalError: local variable 'c_kwargs' referenced before assignment
            return wrapped
    return wrapped

Solusinya adalah dengan mengganti c_kwargs = {} denganc_kwargs.clear()

Jika seseorang memikirkan contoh yang lebih praktis, silakan mengedit posting ini.

Ponkadoodle
sumber
global c_kwargsmungkin juga tidak akan bekerja? Meskipun mungkin globalbukan hal terbaik untuk menggunakan banyak.
fantabolous
3
@fantabolous using globalakan membuat fungsi berperilaku berbeda - semua panggilan ke conf_decorator kemudian akan berbagi variabel c_kwargs yang sama. Saya percaya Python 3 menambahkan nonlocalkata kunci untuk mengatasi masalah ini, dan itu akan berhasil.
Ponkadoodle
1

Selain itu, terkadang instance dikt mungkin menjadi subkelas dikt ( defaultdictmisalnya). Dalam hal ini, penggunaan clearlebih disukai, karena kita tidak harus mengingat jenis persis dari dikt tersebut, dan juga menghindari kode duplikat (menyambungkan garis kliring dengan garis inisialisasi).

x = defaultdict(list)
x[1].append(2)
...
x.clear() # instead of the longer x = defaultdict(list)
Tzach
sumber