Unterschied zwischen dict.clear () und dem Zuweisen von {} in Python

167

Gibt es in Python einen Unterschied zwischen Aufrufen clear()und Zuweisen {}zu einem Wörterbuch? Wenn ja, was ist das? Beispiel:

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

Marcin
quelle
Ich frage mich, ob dies einen Unterschied bei der Speicherbereinigung macht. Ich denke, .clear () sollte besser für das Speichersystem sein.
Xavier Nicollet

Antworten:

285

Wenn Sie eine andere Variable haben, die sich ebenfalls auf dasselbe Wörterbuch bezieht, gibt es einen großen Unterschied:

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

Dies liegt daran, dass beim Zuweisen d = {}ein neues, leeres Wörterbuch erstellt und der dVariablen zugewiesen wird. Dadurch wird d2auf das alte Wörterbuch verwiesen, in dem sich noch Elemente befinden. Jedoch d.clear()löscht das gleiche Wörterbuch , dass dund d2beiden Punkte , an.

Greg Hewgill
quelle
7
Vielen Dank. Das macht Sinn. Ich muss mich noch an die Denkweise gewöhnen, die = Referenzen in Python erstellt ...
Marcin
15
= kopiert Verweise auf Namen. In Python gibt es keine Variablen, nur Objekte und Namen.
tzot
17
Während Ihre Aussage "keine Variablen" pedantisch wahr ist, ist sie hier nicht wirklich hilfreich. Solange in der Python-Sprachdokumentation noch über "Variablen" gesprochen wird, werde ich immer noch den Begriff verwenden: docs.python.org/reference/datamodel.html
Greg Hewgill
9
Ich fand den Kommentar von tzot hilfreich, um mein Denken über Namen, Variablen und Arten von Kopien anzupassen. Es als pedantisch zu bezeichnen, mag Ihre Meinung sein, aber ich finde es ein unfair hartes Urteil.
cfwschmidt
1
Löschen Sie auch clear () nicht das entfernte Objekt im Diktat, auf das möglicherweise noch jemand anderes verweist.
Lorenzo Belli
31

d = {}erstellt eine neue Instanz für, daber alle anderen Verweise verweisen weiterhin auf den alten Inhalt. d.clear()setzt den Inhalt zurück, aber alle Verweise auf dieselbe Instanz sind weiterhin korrekt.

Michel
quelle
21

Zusätzlich zu den in anderen Antworten erwähnten Unterschieden gibt es auch einen Geschwindigkeitsunterschied. d = {} ist doppelt so schnell vorbei:

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
quelle
9
Dies ist nicht in allen Fällen ein gültiger Geschwindigkeitstest, da das Diktat leer ist. Ich denke, ein großes Diktat (oder zumindest ein Teil des Inhalts) würde zu einem viel geringeren Leistungsunterschied führen ... und ich vermute, dass der Garbage Collector d = {} (?)
Rafe
3
@Rafe: Ich denke, wenn wir wissen, dass keine andere Variable auf das Wörterbuch d zeigt, d = {}sollte die Einstellung schneller sein, da die Bereinigung des Ganzen für später dem Garbage Collector überlassen werden kann.
ViFI
8

Zur Veranschaulichung der bereits erwähnten Dinge:

>>> a = {1:2}
>>> id(a)
3073677212L
>>> a.clear()
>>> id(a)
3073677212L
>>> a = {}
>>> id(a)
3073675716L
maxp
quelle
Dies zeigt, dass .cleardas Objekt geändert wird, aber `= {}` ein neues Objekt erstellt.
wizzwizz4
7

Zusätzlich zu @odanos Antwort scheint die Verwendung d.clear()schneller zu sein, wenn Sie das Diktat mehrmals löschen möchten.

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)

Das Ergebnis ist:

20.0367929935
19.6444659233
Lastland
quelle
4
Ich bin nicht sicher, ob der Unterschied signifikant ist. Auf meinem Computer sind die Ergebnisse sowieso umgekehrt!
Aristide
7

Mutationsmethoden sind immer dann nützlich, wenn das ursprüngliche Objekt nicht im Gültigkeitsbereich liegt:

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

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

Durch erneutes Zuweisen des Wörterbuchs wird ein neues Objekt erstellt und das ursprüngliche Objekt nicht geändert.

Karoly Horvath
quelle
4

Eine Sache, die nicht erwähnt wird, ist das Scoping von Problemen. Kein gutes Beispiel, aber hier ist der Fall, in dem ich auf das Problem gestoßen bin:

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

Die Lösung ist zu ersetzen c_kwargs = {}mitc_kwargs.clear()

Wenn sich jemand ein praktischeres Beispiel ausdenkt, können Sie diesen Beitrag bearbeiten.

Ponkadoodle
quelle
global c_kwargswürde wohl auch nein funktionieren? Obwohl es wahrscheinlich globalnicht das Beste ist, viel davon zu verwenden.
fantastisch
3
@fantabolous using globalwürde dazu führen, dass sich die Funktion anders verhält - alle Aufrufe von conf_decorator würden dann dieselbe Variable c_kwargs verwenden. Ich glaube, Python 3 hat das nonlocalSchlüsselwort hinzugefügt , um dieses Problem zu beheben, und das würde funktionieren.
Ponkadoodle
1

Außerdem kann die Diktatinstanz manchmal eine Unterklasse von Dikt sein ( defaultdictzum Beispiel). In diesem Fall wird die Verwendung clearbevorzugt, da wir uns nicht an den genauen Typ des Diktats erinnern müssen und auch doppelten Code vermeiden müssen (Kopplung der Clearing-Linie mit der Initialisierungslinie).

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