Collections.defaultdict unterscheidet sich von normalem Diktat

Lesezeit: 12 Minuten

Benutzeravatar von Lanston
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.

    – Asklepios

    30. Oktober 2016 um 5:54 Uhr


  • Siehe auch: stackoverflow.com/questions/17215400/…

    – dreftymac

    10. Oktober 2017 um 21:05 Uhr

Benutzeravatar von Sven Marnach
Sven Marnach

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

Benutzeravatar von orlp
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.

Zum Beispiel:

somedict = {}
print(somedict[3]) # KeyError

someddict = defaultdict(int)
print(someddict[3]) # print int(), thus 0

  • “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

Benutzeravatar von Somendra Joshi
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

So verwenden Sie defaultdict

defaultdict importieren

>>> from collections import defaultdict

defaultdict initialisieren

Initialisieren Sie es durch Übergeben

Callable als erstes Argument (obligatorisch)

>>> d_int = defaultdict(int)
>>> d_list = defaultdict(list)
>>> def foo():
...     return 'default value'
... 
>>> d_foo = defaultdict(foo)
>>> d_int
defaultdict(<type 'int'>, {})
>>> d_list
defaultdict(<type 'list'>, {})
>>> d_foo
defaultdict(<function foo at 0x7f34a0a69578>, {})

**kwargs als zweites Argument (optional)

>>> d_int = defaultdict(int, a=10, b=12, c=13)
>>> d_int
defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12})

oder

>>> kwargs = {'a':10,'b':12,'c':13}
>>> d_int = defaultdict(int, **kwargs)
>>> d_int
defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12})

Wie funktioniert es

Da es sich um eine untergeordnete Klasse des Standardwörterbuchs handelt, kann es dieselben Funktionen ausführen.

Aber wenn ein unbekannter Schlüssel übergeben wird, wird der Standardwert anstelle eines Fehlers zurückgegeben. Zum Beispiel:

>>> d_int['a']
10
>>> d_int['d']
0
>>> d_int
defaultdict(<type 'int'>, {'a': 10, 'c': 13, 'b': 12, 'd': 0})

Falls Sie den Standardwert ändern möchten, überschreiben Sie default_factory:

>>> d_int.default_factory = lambda: 1
>>> d_int['e']
1
>>> d_int
defaultdict(<function <lambda> at 0x7f34a0a91578>, {'a': 10, 'c': 13, 'b': 12, 'e': 1, 'd': 0})

oder

>>> def foo():
...     return 2
>>> d_int.default_factory = foo
>>> d_int['f']
2
>>> d_int
defaultdict(<function foo at 0x7f34a0a0a140>, {'a': 10, 'c': 13, 'b': 12, 'e': 1, 'd': 0, 'f': 2})

Beispiele in der Frage

Beispiel 1

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


Benutzer-Avatar von dimension
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.

from collections import defaultdict
ice_cream = defaultdict(lambda: 'Vanilla')

ice_cream['Sarah'] = 'Chunky Monkey'
ice_cream['Abdul'] = 'Butter Pecan'

print(ice_cream['Sarah'])
>>>Chunky Monkey

print(ice_cream['Joe'])
>>>Vanilla

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.

Benutzeravatar von varagrawal
varagrawal

Hier gibt es eine großartige Erklärung für defaultdicts: http://ludovf.net/blog/python-collections-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.

Benutzeravatar von Diego Queiroz
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).

Einige mögen argumentieren, dass es eine Leistungsbetrachtung gibt, aber dieses Thema ist ein Minenfeld. Dieser Beitrag zeigt, dass beispielsweise die Verwendung von defaultdict keinen großen Leistungsgewinn bringt.

IMO, defaultdict ist eine Sammlung, die dem Code mehr Verwirrung als Nutzen bringt. Für mich unbrauchbar, aber andere mögen das anders sehen.

Benutzeravatar der Community
Gemeinschaft

Da es um die Frage geht, “wie es funktioniert”, möchten einige Leser vielleicht mehr Schrauben und Muttern sehen. Konkret handelt es sich um die fragliche Methode __missing__(key) Methode. Sehen: https://docs.python.org/2/library/collections.html#defaultdict-objects .

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):

>>> dd2 = defaultdict(lambda: 0)
>>> dd2
defaultdict(<function <lambda> at 0x02C4C130>, {})
>>> dd2['a']
0
>>> dd2
defaultdict(<function <lambda> at 0x02C4C130>, {'a': 0})
>>> 

Und mit einem anderen Standardwert:

>>> dd3 = defaultdict(lambda: 1)
>>> dd3
defaultdict(<function <lambda> at 0x02C4C170>, {})
>>> dd3['a']
1
>>> dd3
defaultdict(<function <lambda> at 0x02C4C170>, {'a': 1})
>>> 

1449120cookie-checkCollections.defaultdict unterscheidet sich von normalem Diktat

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy