Python'da dict.clear () ve {} atama arasındaki fark


167

Python'da, sözlüğü arama clear()ve atama arasında bir fark var {}mı? Eğer evet ise, bu nedir? Misal:

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


Bunun çöp toplama kısmında bir fark yaratıp yaratmadığını merak ediyorum. Bellek sistemi için .clear () daha iyi olmalı gibi hissediyorum.
Xavier Nicollet

Yanıtlar:


285

Aynı sözlüğe başvuran başka bir değişkeniniz varsa, büyük bir fark vardır:

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

Bunun nedeni atamanın d = {}yeni, boş bir sözlük oluşturması ve ddeğişkene atamasıdır. Bu d2, hala içindeki öğelerle eski sözlüğe işaret eder. Ancak, d.clear()aynı sözlüğü siler dve d2her ikisi de işaret eder.


7
Teşekkürler. Bu mantıklı. Hala python referanslar oluşturur zihniyet alışmak zorunda ...
Marcin

15
= isimlere yapılan referansları kopyalar. Python'da değişken yok, sadece nesneler ve isimler var.
tzot

17
"Değişken yok" ifadeniz bilgelik açısından doğru olsa da, burada gerçekten yararlı değildir. Python dil belgeleri hala "değişkenler" hakkında konuştuğu sürece, hala şu terimi kullanacağım: docs.python.org/reference/datamodel.html
Greg Hewgill

9
Tzot'un yorumunu adlar, değişkenler ve kopya türleri hakkındaki düşüncelerimi ayarlamada yararlı buldum. Bilgiçlik tasviri demek sizin fikriniz olabilir, ancak haksız sert bir yargı olduğunu düşünüyorum.
cfwschmidt

1
Ayrıca clear (), başka bir kişi tarafından hala başvurulabilecek olan dikte kaldırılan nesneyi yok etmeyin.
Lorenzo Belli

31

d = {}için yeni bir örnek oluşturur, dancak diğer referansların tümü eski içeriği gösterir. d.clear()içeriği sıfırlar, ancak aynı örneğe yapılan tüm referanslar yine de doğru olur.


21

Diğer cevaplarda belirtilen farklılıklara ek olarak, bir hız farkı da vardır. d = {} iki kat daha hızlı bitti:

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

9
Karar boş olduğu için bu gerçekten tüm durumlar için geçerli bir hız testi değildir. Sanırım büyük bir diksiyon yapmak (ya da en azından bir içerik) çok daha küçük bir performans farkı yaratacaktır ... artı çöp toplayıcının d = {} (?)
Rafe

3
@Rafe: Bence nokta, başka bir değişkenin sözlük d'e işaret etmediğini bilersek, o zaman ayar d = {}daha hızlı olmalıdır çünkü bütün temizlik daha sonra Çöp Toplayıcısına bırakılabilir.
ViFI

8

Daha önce bahsettiğimiz şeylerin bir örneği olarak:

>>> a = {1:2}
>>> id(a)
3073677212L
>>> a.clear()
>>> id(a)
3073677212L
>>> a = {}
>>> id(a)
3073675716L

Bu, .clearnesneyi değiştirdiğini ancak `= {}` yeni bir nesne oluşturduğunu gösterir.
wizzwizz4

7

@Odano'nun cevabına ek olarak, bu dikdörtgeni d.clear()birçok kez temizlemek isterseniz kullanmak daha hızlı görünüyor .

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)

Sonuç:

20.0367929935
19.6444659233

4
Aradaki farkın anlamlı olduğundan emin değilim. Her neyse, makinemde, sonuçlar tam tersi!
Aristide

7

Orijinal nesne kapsamda değilse, mutasyon yöntemleri her zaman yararlıdır:

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

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

Sözlüğün yeniden atanması yeni bir nesne oluşturur ve orijinalini değiştirmez.


4

Bahsetmediğim bir şey, kapsam belirleme sorunudur. Harika bir örnek değil, ama burada sorunla karşılaştığım durum:

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

Çözelti değiştirmektir c_kwargs = {}ilec_kwargs.clear()

Birisi daha pratik bir örnek düşünürse, bu yayını düzenlemek için çekinmeyin.


global c_kwargsmuhtemelen hayır çalışır? Her ne kadar muhtemelen globalbir sürü kullanmak için en iyi şey değil.
harika

3
@fantabolous kullanarak globalişlev farklı davranır - conf_decorator'a yapılan tüm çağrılar aynı c_kwargs değişkenini paylaşır. Python 3'ün nonlocalbu sorunu çözmek için anahtar kelimeyi eklediğine inanıyorum ve bu işe yarayacaktır.
Ponkadoodle

1

Buna ek olarak, bazen dict örneği bir dict alt sınıfı olabilir ( defaultdictörneğin). Bu durumda, cleardiktenin tam tipini hatırlamak zorunda olmadığımız ve yinelenen koddan (temizleme hattını başlangıç ​​çizgisine bağlayan) kullanmak zorunda olmadığımız için kullanmak tercih edilir.

x = defaultdict(list)
x[1].append(2)
...
x.clear() # instead of the longer x = defaultdict(list)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.