Collections.defaultdict unterscheidet sich von normalem Diktat
Lesezeit: 12 Minuten
Lanston
Ich habe die Beispiele in Python-Dokumenten gelesen, kann aber immer noch nicht herausfinden, was diese Methode bedeutet. Kann jemand helfen? Hier sind zwei Beispiele aus der Python-Dokumentation
>>> from collections import defaultdict
>>> s="mississippi"
>>> d = defaultdict(int)
>>> for k in s:
... d[k] += 1
...
>>> d.items()
dict_items([('m', 1), ('i', 4), ('s', 4), ('p', 2)])
Und
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> for k, v in s:
... d[k].append(v)
...
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
Die Parameter int Und list sind für was?
Übrigens, je nach Anwendungsfall, Vergiss es nicht um das Defaultdict für den schreibgeschützten Gebrauch einzufrieren, indem Sie es setzen default_factory = None nachdem Sie das defaultdict ausgefüllt haben. Siehe diese Frage.
Normalerweise wirft ein Python-Wörterbuch a KeyError wenn Sie versuchen, ein Element mit einem Schlüssel abzurufen, der sich derzeit nicht im Wörterbuch befindet. Der defaultdict im Gegensatz dazu werden einfach alle Elemente erstellt, auf die Sie zugreifen möchten (vorausgesetzt natürlich, sie existieren noch nicht). Um ein solches “Standard”-Element zu erstellen, ruft es das Funktionsobjekt auf, das Sie an den Konstruktor übergeben (genauer gesagt, es ist ein beliebiges “aufrufbares” Objekt, das Funktions- und Typobjekte enthält). Für das erste Beispiel werden Standardelemente mit erstellt int()die das Integer-Objekt zurückgibt 0. Für das zweite Beispiel werden Standardelemente mit erstellt list()die ein neues leeres Listenobjekt zurückgibt.
Unterscheidet es sich funktional von der Verwendung von d.get(key, default_val) ?
– Ambarisch
1. Mai 2019 um 1:31 Uhr
@Ambareesh d.get(key, default) wird niemals Ihr Wörterbuch ändern – es wird nur den Standardwert zurückgeben und das Wörterbuch unverändert lassen. defaultdictauf der anderen Seite wird Einfügung einen Schlüssel ins Wörterbuch, wenn es noch nicht da ist. Das ist ein großer Unterschied; Sehen Sie sich die Beispiele in der Frage an, um zu verstehen, warum.
– Sven Marnach
2. Mai 2019 um 19:10 Uhr
Woher wissen wir, was der Standardwert für jeden Typ ist? 0 für int() und [] for list() sind intuitiv, es kann aber auch komplexere oder selbstdefinierte Typen geben.
– Sean
11. März 2020 um 10:40 Uhr
@ Sean defaultdict ruft den Konstruktor auf, den Sie übergeben. Wenn Sie einen Typ übergeben TWerte werden mit konstruiert T(). Nicht alle Typen können konstruiert werden, ohne irgendwelche Parameter zu übergeben. Wenn Sie einen solchen Typ konstruieren möchten, benötigen Sie eine Wrapper-Funktion oder ähnliches functools.partial(T, arg1, arg2).
– Sven Marnach
11. März 2020 um 10:58 Uhr
Oder noch einfacher: ein Lambda. defaultdict(lambda : T(arg1, arg2)).
– Mees de Vries
18. August 2020 um 11:24 Uhr
Orlp
defaultdict bedeutet, wenn ein Schlüssel nicht im Wörterbuch gefunden wird, dann statt a KeyError geworfen wird, wird ein neuer Eintrag erstellt. Der Typ dieses neuen Eintrags wird durch das Argument von defaultdict angegeben.
“Der Typ dieses neuen Paares wird durch das Argument von defaultdict angegeben.” Beachten Sie, dass das Argument sein kann beliebig aufrufbares Objekt – nicht nur Typfunktionen. Wenn zum Beispiel foo eine Funktion wäre, die “bar” zurückgibt, könnte foo als Argument für default dict verwendet werden, und wenn auf einen nicht vorhandenen Schlüssel zugegriffen würde, würde sein Wert auf “bar” gesetzt werden.
– lf215
29. Juli 2013 um 5:56 Uhr
Oder wenn Sie nur “bar” zurückgeben möchten: somedict = defaultdict(lambda:”bar”)
– Michael Scott Asato Cuthbert
2. Juni 2014 um 21:23 Uhr
Vierte Zeile zurückgegeben 0 die ganze Zahl, wenn es war someddict = defaultdict(list) es kehrt zurück [ ]. Ist 0 die Standard-Ganzzahl? Oder [ ] die Standardliste?
– Gathide
5. Januar 2017 um 7:30 Uhr
Weder. 0 ist unveränderlich – in CPython alle Werte aus -5 Zu 256 sind zwischengespeicherte Singletons, aber dies ist ein implementierungsspezifisches Verhalten – in beiden Fällen wird jedes Mal eine neue Instanz mit “erstellt”. int() oder list(). Dieser Weg, d[k].append(v) kann funktionieren, ohne das Wörterbuch mit Verweisen auf dieselbe Liste zu füllen, die gerendert werden würde defaultdict fast nutzlos. Wenn dies das Verhalten wäre, defaultdict würde einen Wert, kein Lambda, als Parameter nehmen. (Entschuldigung für die schreckliche Erklärung!)
– wizzwizz4
7. Oktober 2017 um 8:58 Uhr
Somendra Joshi
Versäumnis
“Das Standardwörterbuch enthält die Methode setdefault() zum Abrufen eines Werts und zum Festlegen eines Standardwerts, wenn der Wert nicht existiert. Im Gegensatz dazu defaultdict lässt den Aufrufer den Standardwert (zurückzugebender Wert) im Voraus angeben, wenn der Container initialisiert wird.”
wie definiert durch Doug Hellmann In Die Python-Standardbibliothek am Beispiel
Da int als default_factory übergeben wurde, gibt jeder unbekannte Schlüssel standardmäßig 0 zurück.
Wenn die Zeichenfolge nun in der Schleife übergeben wird, wird die Anzahl dieser Alphabete in d erhöht.
>>> s="mississippi"
>>> d = defaultdict(int)
>>> d.default_factory
<type 'int'>
>>> for k in s:
... d[k] += 1
>>> d.items()
[('i', 4), ('p', 2), ('s', 4), ('m', 1)]
>>> d
defaultdict(<type 'int'>, {'i': 4, 'p': 2, 's': 4, 'm': 1})
Beispiel 2
Da eine Liste als default_factory übergeben wurde, wird jeder unbekannte (nicht vorhandene) Schlüssel zurückgegeben [ ](d. h. Liste) standardmäßig.
Wenn nun die Liste der Tupel in der Schleife übergeben wird, wird der Wert in d angehängt[color]
>>> s = [('yellow', 1), ('blue', 2), ('yellow', 3), ('blue', 4), ('red', 1)]
>>> d = defaultdict(list)
>>> d.default_factory
<type 'list'>
>>> for k, v in s:
... d[k].append(v)
>>> d.items()
[('blue', [2, 4]), ('red', [1]), ('yellow', [1, 3])]
>>> d
defaultdict(<type 'list'>, {'blue': [2, 4], 'red': [1], 'yellow': [1, 3]})
Danke für die Antwort. Weißt du, wie man die Konstante immer anders macht? Ich erkläre: defaultdict(lambda: 'string', **kwargs) wird nicht wie erwartet funktionieren, da alle neuen Schlüssel die gleiche Instanz von ‘string’ teilen. Wie kann ich jedes Mal eine Kopie bereitstellen? Beachten Sie, dass defaultdict(lambda: copy.copy('string'), **kwargs) funktioniert nicht, da copy nur einmal ausgewertet wird.
– Dr_Zaszuś
23. Juni 2020 um 9:48 Uhr
Abmessungen
Wörterbücher sind eine bequeme Möglichkeit, Daten für den späteren Abruf nach Namen (Schlüssel) zu speichern. Schlüssel müssen eindeutige, unveränderliche Objekte sein und sind normalerweise Zeichenfolgen. Die Werte in einem Wörterbuch können beliebig sein. Bei vielen Anwendungen handelt es sich bei den Werten um einfache Typen wie Ganzzahlen und Zeichenfolgen.
Interessanter wird es, wenn die Werte in einem Wörterbuch Sammlungen sind (Listen, Diktate usw.). In diesem Fall muss der Wert (eine leere Liste oder ein leeres Diktat) initialisiert werden, wenn ein bestimmter Schlüssel zum ersten Mal verwendet wird. Während dies manuell relativ einfach zu bewerkstelligen ist, automatisiert und vereinfacht der Typ defaultdict diese Art von Vorgängen. Ein defaultdict funktioniert genauso wie ein normales dict, aber es wird mit einer Funktion („default factory“) initialisiert, die keine Argumente akzeptiert und den Standardwert für einen nicht vorhandenen Schlüssel bereitstellt.
Ein Defaultdict wird niemals einen KeyError auslösen. Jeder Schlüssel, der nicht vorhanden ist, erhält den Wert, der von der Standardfabrik zurückgegeben wird.
Hier ist ein weiteres Beispiel dafür, wie wir mit defaultdict die Komplexität reduzieren können
from collections import defaultdict
# Time complexity O(n^2)
def delete_nth_naive(array, n):
ans = []
for num in array:
if ans.count(num) < n:
ans.append(num)
return ans
# Time Complexity O(n), using hash tables.
def delete_nth(array,n):
result = []
counts = defaultdict(int)
for i in array:
if counts[i] < n:
result.append(i)
counts[i] += 1
return result
x = [1,2,3,1,2,1,2,3]
print(delete_nth(x, n=2))
print(delete_nth_naive(x, n=2))
Wenn Sie also ein Wörterbuch benötigen und der Wert jedes Elements mit einem Standardwert beginnen sollte, verwenden Sie ein defaultdict.
Grundsätzlich die Parameter int Und Liste sind Funktionen, die Sie übergeben. Denken Sie daran, dass Python Funktionsnamen als Argumente akzeptiert. int gibt standardmäßig 0 zurück und Liste gibt eine leere Liste zurück, wenn sie mit Klammern aufgerufen wird.
In normalen Wörterbüchern, wenn ich in Ihrem Beispiel versuche, anzurufen d[a], erhalte ich einen Fehler (KeyError), da nur die Schlüssel m, s, i und p existieren und der Schlüssel a nicht initialisiert wurde. Aber in einem Defaultdict nimmt es einen Funktionsnamen als Argument, wenn Sie versuchen, eine Taste zu verwenden, die nicht initialisiert wurde, ruft es einfach die übergebene Funktion auf und weist ihren Rückgabewert als Wert der neuen Taste zu.
Diego Queiroz
Das Verhalten von defaultdict kann leicht nachgeahmt werden dict.setdefault anstatt d[key] bei jedem Anruf.
Mit anderen Worten, der Code:
from collections import defaultdict
d = defaultdict(list)
print(d['key']) # empty list []
d['key'].append(1) # adding constant 1 to the list
print(d['key']) # list containing the constant [1]
ist äquivalent zu:
d = dict()
print(d.setdefault('key', list())) # empty list []
d.setdefault('key', list()).append(1) # adding constant 1 to the list
print(d.setdefault('key', list())) # list containing the constant [1]
Der einzige Unterschied ist, dass mit defaultdictder Listenkonstruktor wird nur einmal aufgerufen und mit dict.setdefault Der Listenkonstruktor wird häufiger aufgerufen (aber der Code kann umgeschrieben werden, um dies zu vermeiden, falls dies wirklich erforderlich ist).
Konkret zeigt diese Antwort, wie man sie nutzt __missing__(key) auf praktische Weise: https://stackoverflow.com/a/17956989/1593924
Um zu verdeutlichen, was „aufrufbar“ bedeutet, hier eine interaktive Sitzung (ab 2.7.6, sollte aber auch in v3 funktionieren):
>>> x = int
>>> x
<type 'int'>
>>> y = int(5)
>>> y
5
>>> z = x(5)
>>> z
5
>>> from collections import defaultdict
>>> dd = defaultdict(int)
>>> dd
defaultdict(<type 'int'>, {})
>>> dd = defaultdict(x)
>>> dd
defaultdict(<type 'int'>, {})
>>> dd['a']
0
>>> dd
defaultdict(<type 'int'>, {'a': 0})
Das war die typischste Verwendung von defaultdict (abgesehen von der sinnlosen Verwendung der x-Variablen). Sie können dasselbe mit 0 als explizitem Standardwert tun, aber nicht mit einem einfachen Wert:
>>> dd2 = defaultdict(0)
Traceback (most recent call last):
File "<pyshell#7>", line 1, in <module>
dd2 = defaultdict(0)
TypeError: first argument must be callable
Stattdessen funktioniert Folgendes, weil es eine einfache Funktion übergibt (es erstellt spontan eine namenlose Funktion, die keine Argumente akzeptiert und immer 0 zurückgibt):
Übrigens, je nach Anwendungsfall, Vergiss es nicht um das Defaultdict für den schreibgeschützten Gebrauch einzufrieren, indem Sie es setzen
default_factory = None
nachdem Sie das defaultdict ausgefüllt haben. Siehe diese Frage.– Asklepios
30. Oktober 2016 um 5:54 Uhr
Siehe auch: stackoverflow.com/questions/17215400/…
– dreftymac
10. Oktober 2017 um 21:05 Uhr