Heim  >  Artikel  >  Backend-Entwicklung  >  Ausführliche Erklärung von defaultdict in Python (Codebeispiel)

Ausführliche Erklärung von defaultdict in Python (Codebeispiel)

不言
不言nach vorne
2018-10-25 17:34:433100Durchsuche

Dieser Artikel bietet Ihnen eine detaillierte Erklärung (Codebeispiel) von defaultdict in Python. Ich hoffe, dass er Ihnen als Referenz dienen wird.

Standardwerte können sehr praktisch sein

Wie wir alle wissen, kommt es in Python zu einer KeyError-Ausnahme, wenn Sie auf einen Schlüssel zugreifen, der nicht im Wörterbuch vorhanden ist wird ausgelöst (in JavaScript wird undefiniert zurückgegeben, wenn ein bestimmter Schlüssel nicht im Objektattribut vorhanden ist). Manchmal ist es jedoch sehr praktisch, für jeden Schlüssel im Wörterbuch einen Standardwert zu haben. Zum Beispiel das folgende Beispiel:

strings = ('puppy', 'kitten', 'puppy', 'puppy',
           'weasel', 'puppy', 'kitten', 'puppy')
counts = {}
for kw in strings:
    counts[kw] += 1

Dieses Beispiel zählt, wie oft ein Wort in Zeichenfolgen vorkommt, und zeichnet es im Zählwörterbuch auf. Jedes Mal, wenn ein Wort erscheint, wird der im Schlüssel gespeicherte Wert entsprechend counts um 1 erhöht. Tatsächlich wird beim Ausführen dieses Codes eine KeyError-Ausnahme ausgelöst, wenn jedes Wort zum ersten Mal gezählt wird. Da es in Pythons Diktat keinen Standardwert gibt, kann dies in der Python-Befehlszeile überprüft werden:

>>> counts = dict()
>>> counts
{}
>>> counts['puppy'] += 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: &#39;puppy&#39;

Verwenden Sie Urteilsaussagen zur Überprüfung

In diesem Fall besteht die erste denkbare Möglichkeit darin, einen Standardwert von 1 im entsprechenden Schlüssel in counts zu speichern, wenn das Wort zum ersten Mal gezählt wird. Dies erfordert das Hinzufügen einer Urteilsaussage während der Verarbeitung:
strings = (&#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;, &#39;puppy&#39;,
           &#39;weasel&#39;, &#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;)
counts = {}
for kw in strings:
    if kw not in counts:
        counts[kw] = 1
    else:
        counts[kw] += 1
# counts:
# {&#39;puppy&#39;: 5, &#39;weasel&#39;: 1, &#39;kitten&#39;: 2}

Verwenden Sie die Methode dict.setdefault()

Sie können den Standardwert auch über die Methode dict.setdefault() festlegen:

strings = (&#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;, &#39;puppy&#39;,
           &#39;weasel&#39;, &#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;)
counts = {}
for kw in strings:
    counts.setdefault(kw, 0)
    counts[kw] += 1

Die Methode dict.setdefault() empfängt zwei Parameter. Der erste Parameter ist der Name des Schlüssels und der zweite Parameter ist der Standardwert. Wenn der angegebene Schlüssel nicht im Wörterbuch vorhanden ist, wird der im Parameter angegebene Standardwert zurückgegeben. Andernfalls wird der im Wörterbuch gespeicherte Wert zurückgegeben. Der Code in der for-Schleife kann mithilfe des Rückgabewerts der Methode dict.setdefault() umgeschrieben werden, um ihn prägnanter zu gestalten:

strings = (&#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;, &#39;puppy&#39;,
           &#39;weasel&#39;, &#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;)
counts = {}
for kw in strings:
    counts[kw] = counts.setdefault(kw, 0) + 1

Verwenden Sie die Klasse „collections.defaultdict“

Obwohl die obige Methode verwendet wird ist bis zu einem gewissen Grad Dies löst das Problem, dass es im Diktat keinen Standardwert gibt, aber zu diesem Zeitpunkt werden wir uns fragen, ob es ein Wörterbuch gibt, das selbst die Funktion des Standardwerts bereitstellt? Die Antwort lautet: Ja, es istcollections.defaultdict.

Die defaultdict-Klasse ähnelt einem Diktat, wird jedoch mit einem Typ initialisiert:

>>> from collections import defaultdict
>>> dd = defaultdict(list)
>>> dd
defaultdict(<type &#39;list&#39;>, {})

Die Initialisierungsfunktion der defaultdict-Klasse akzeptiert einen Typ als Parameter und kann instanziiert werden, wenn der Schlüssel, auf den zugegriffen wird, dies tut nicht vorhanden Ändern Sie einen Wert als Standardwert:

>>> dd[&#39;foo&#39;]
[]
>>> dd
defaultdict(<type &#39;list&#39;>, {&#39;foo&#39;: []})
>>> dd[&#39;bar&#39;].append(&#39;quux&#39;)
>>> dd
defaultdict(<type &#39;list&#39;>, {&#39;foo&#39;: [], &#39;bar&#39;: [&#39;quux&#39;]})

Es ist zu beachten, dass diese Form des Standardwerts nur gültig ist, wenn auf dict[key] oder dict.__getitem__(key) zugegriffen wird. Die Gründe dafür werden im Folgenden vorgestellt.

>>> from collections import defaultdict
>>> dd = defaultdict(list)
>>> &#39;something&#39; in dd
False
>>> dd.pop(&#39;something&#39;)
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: &#39;pop(): dictionary is empty&#39;
>>> dd.get(&#39;something&#39;)
>>> dd[&#39;something&#39;]
[]

Diese Klasse akzeptiert nicht nur den Typnamen als Parameter der Initialisierungsfunktion, sondern kann auch jede aufrufbare Funktion ohne Parameter verwenden. Zu diesem Zeitpunkt wird das Rückgabeergebnis der Funktion als Standardwert verwendet , wodurch die Standardwerte flexibler werden. Im Folgenden wird anhand eines Beispiels veranschaulicht, wie die benutzerdefinierte Funktion null () ohne Parameter als Parameter der Initialisierungsfunktion verwendet wird:

>>> from collections import defaultdict
>>> def zero():
...     return 0
...
>>> dd = defaultdict(zero)
>>> dd
defaultdict(<function zero at 0xb7ed2684>, {})
>>> dd[&#39;foo&#39;]
0
>>> dd
defaultdict(<function zero at 0xb7ed2684>, {&#39;foo&#39;: 0})

Verwenden Sie collections.defaultdict, um das anfängliche Wortzählproblem zu lösen. Der Code lautet wie folgt :

from collections import defaultdict
strings = (&#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;, &#39;puppy&#39;,
           &#39;weasel&#39;, &#39;puppy&#39;, &#39;kitten&#39;, &#39;puppy&#39;)
counts = defaultdict(lambda: 0)  # 使用lambda来定义简单的函数
for s in strings:
    counts[s] += 1

Wie die Defaultdict-Klasse implementiert wird

Durch den obigen Inhalt müssen Sie die Verwendung der Defaultdict-Klasse verstanden haben. Wie implementiert man also die Standardwertfunktion in der Defaultdict-Klasse? Der Schlüssel dazu ist die Verwendung der Methode __missing__():

>>> from collections import defaultdict
>>> print defaultdict.__missing__.__doc__
__missing__(key) # Called by __getitem__ for missing key; pseudo-code:
  if self.default_factory is None: raise KeyError(key)
  self[key] = value = self.default_factory()
  return value

Wenn wir uns den Dokumentstring der Methode __missing__() ansehen, können wir sehen, dass wir die Methode __getitem__() verwenden, um auf ein nicht vorhandenes Objekt zuzugreifen key (Die Form dict[key] ist eigentlich eine vereinfachte Form der Methode __getitem__()), die die Methode __missing__() aufruft, um den Standardwert abzurufen und den Schlüssel zum Wörterbuch hinzuzufügen.

Eine ausführliche Einführung in die Methode __missing__() finden Sie im Abschnitt „Mapping Types – dict“ in der offiziellen Python-Dokumentation.

Ab Version 2.5 im Dokument eingeführt: Wenn eine von dict abgeleitete Unterklasse die Methode __missing__() definiert, ruft dict[key] beim Zugriff auf einen nicht vorhandenen Schlüssel die Methode __missing__() auf, um sie abzurufen Standardwert.

Daraus ist ersichtlich, dass dict zwar die Methode __missing__() unterstützt, diese Methode jedoch nicht in dict selbst vorhanden ist. Stattdessen muss diese Methode in der abgeleiteten Unterklasse implementiert werden. Dies kann leicht überprüft werden:

>>> print dict.__missing__.__doc__
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: type object &#39;dict&#39; has no attribute &#39;__missing__&#39;

Gleichzeitig können wir weitere Experimente durchführen, eine Unterklasse Missing definieren und die Methode __missing__() implementieren:

>>> class Missing(dict):
...     def __missing__(self, key):
...         return 'missing'
...
>>> d = Missing()
>>> d
{}
>>> d['foo']
'missing'
>>> d
{}

Das Rückgabeergebnis spiegelt __missing__( ) wider. Methode funktioniert. Auf dieser Basis modifizieren wir die Methode __missing__() leicht, sodass diese Unterklasse einen Standardwert für nicht vorhandene Schlüssel wie die Klasse defautldict festlegt:

>>> class Defaulting(dict):
...     def __missing__(self, key):
...         self[key] = &#39;default&#39;
...         return &#39;default&#39;
...
>>> d = Defaulting()
>>> d
{}
>>> d[&#39;foo&#39;]
&#39;default&#39;
>>> d
{&#39;foo&#39;: &#39;default&#39;}

Implementierung der Funktion von defaultdict in älteren Versionen von Python

Die Klasse „defaultdict“ wurde nach Version 2.5 hinzugefügt und wird in einigen älteren Versionen nicht unterstützt. Daher ist es erforderlich, eine kompatible Klasse „defaultdict“ für ältere Versionen zu implementieren. Dies ist eigentlich sehr einfach. Obwohl die Leistung möglicherweise nicht so gut ist wie die Standardklasse in Version 2.5, ist sie funktional dieselbe.

Zuerst muss die Methode __getitem__() die Methode __missing__() aufrufen, wenn der Zugriffsschlüssel fehlschlägt:

class defaultdict(dict):
    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)

Zweitens muss die Methode __missing__() implementiert werden, um den Standardwert festzulegen:

class defaultdict(dict):
    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)
    def __missing__(self, key):
        self[key] = value = self.default_factory()
        return value

Dann muss die Initialisierungsfunktion __init__() der Defaultdict-Klasse Typ- oder aufrufbare Funktionsparameter akzeptieren:

class defaultdict(dict):
    def __init__(self, default_factory=None, *a, **kw):
        dict.__init__(self, *a, **kw)
        self.default_factory = default_factory    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)
    def __missing__(self, key):
        self[key] = value = self.default_factory()
        return value

最后,综合以上内容,通过以下方式完成兼容新旧Python版本的代码:

try:
    from collections import defaultdictexcept ImportError:
    class defaultdict(dict):
      def __init__(self, default_factory=None, *a, **kw):
          dict.__init__(self, *a, **kw)
          self.default_factory = default_factory      def __getitem__(self, key):
          try:
              return dict.__getitem__(self, key)
          except KeyError:
              return self.__missing__(key)

      def __missing__(self, key):
          self[key] = value = self.default_factory()
          return value

Das obige ist der detaillierte Inhalt vonAusführliche Erklärung von defaultdict in Python (Codebeispiel). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:csdn.net. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen