Maison  >  Article  >  développement back-end  >  Explication détaillée de defaultdict en Python (exemple de code)

Explication détaillée de defaultdict en Python (exemple de code)

不言
不言avant
2018-10-25 17:34:433098parcourir

Cet article vous apporte une explication détaillée (exemple de code) de defaultdict en Python. Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Les valeurs par défaut peuvent être très pratiques

Comme nous le savons tous, en Python, si vous accédez à une clé qui n'existe pas dans le dictionnaire, une exception KeyError sera déclenché (en JavaScript, si une certaine clé n'existe pas dans l'attribut d'objet, renvoie undéfini). Mais il est parfois très pratique d’avoir une valeur par défaut pour chaque clé du dictionnaire. Par exemple, l'exemple suivant :

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

Cet exemple compte le nombre de fois qu'un mot apparaît dans les chaînes et l'enregistre dans le dictionnaire des comptes. A chaque apparition d'un mot, la valeur stockée dans la clé correspondant aux comptes est incrémentée de 1. Mais en fait, l'exécution de ce code générera une exception KeyError. Le moment de l'occurrence correspond au moment où chaque mot est compté pour la première fois. Comme il n'y a pas de valeur par défaut dans le dict de Python, cela peut être vérifié dans la ligne de commande Python :

>>> counts = dict()
>>> counts
{}
>>> counts['puppy'] += 1
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: &#39;puppy&#39;
Utilisez des déclarations de jugement pour vérifier

Dans ce cas, la première façon possible de penser est de stocker une valeur par défaut de 1 dans la clé correspondante en nombres lorsque le mot est compté pour la première fois. Cela nécessite l'ajout d'une déclaration de jugement pendant le traitement :

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}
Utilisez la méthode dict.setdefault()

Vous pouvez également définir la valeur par défaut via la méthode dict.setdefault() :

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

La méthode dict.setdefault() reçoit deux paramètres Le premier paramètre est le nom de la clé et le deuxième paramètre est la valeur par défaut. Si la clé donnée n'existe pas dans le dictionnaire, la valeur par défaut fournie dans le paramètre est renvoyée ; sinon, la valeur enregistrée dans le dictionnaire est renvoyée ; Le code de la boucle for peut être réécrit en utilisant la valeur de retour de la méthode dict.setdefault() pour le rendre plus concis :


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
Utilisez la classe collections.defaultdict

Bien que La méthode ci-dessus peut être utilisée dans une certaine mesure. Dans une certaine mesure, elle résout le problème de l'absence de valeur par défaut dans dict, mais à ce moment-là, nous nous demanderons s'il existe un dictionnaire qui fournit lui-même la fonction de valeur par défaut ? La réponse est oui, c'est collections.defaultdict.

La classe defaultdict est comme un dict, mais elle est initialisée à l'aide d'un type :

>>> from collections import defaultdict
>>> dd = defaultdict(list)
>>> dd
defaultdict(<type &#39;list&#39;>, {})
La fonction d'initialisation de la classe defaultdict accepte un type comme paramètre Lorsque la clé accessible n'existe pas. , Vous pouvez instancier une valeur comme valeur par défaut :

>>> 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;]})
Il convient de noter que cette forme de valeur par défaut n'est valable que lors d'un accès via

ou dict[key]. sera présenté ci-dessous. dict.__getitem__(key)

>>> 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;]
[]
En plus d'accepter le nom du type comme paramètre de la fonction d'initialisation, cette classe peut également utiliser n'importe quelle fonction appelable sans paramètres. À ce moment-là, le résultat de retour de la fonction sera utilisé comme paramètre. valeur par défaut, de sorte que la valeur par défaut La valeur est plus flexible. Ce qui suit utilise un exemple pour illustrer comment utiliser la fonction personnalisée zero() sans paramètres comme paramètre de la fonction d'initialisation :

>>> 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})
Utilisez

pour résoudre le problème de statistiques de mots initial, le code est comme suit : collections.defaultdict

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
Comment la classe defaultdict est implémentée

Grâce au contenu ci-dessus, vous devez avoir compris l'utilisation de la classe defaultdict, donc comment implémenter la fonction de valeur par défaut dans le classe defaultdict Drap de laine ? La clé pour cela est d'utiliser la méthode __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
En regardant la docstring de la méthode __missing__(), vous pouvez voir que lorsque vous utilisez la méthode __getitem__() pour accéder à un non- clé existante (la forme dict[key] est en fait une forme simplifiée de la méthode __getitem__()), la méthode __missing__() sera appelée pour obtenir la valeur par défaut et ajouter la clé au dictionnaire.

Pour une introduction détaillée à la méthode __missing__(), veuillez vous référer à la section « Mapping Types — dict » dans la documentation officielle de Python.

Introduit dans le document, à partir de la version 2.5, si une sous-classe dérivée de dict définit la méthode __missing__(), lors de l'accès à une clé inexistante, dict[key] appellera la méthode __missing__() pour obtenir valeur par défaut.

On peut voir à partir de cela que bien que dict prenne en charge la méthode __missing__(), cette méthode n'existe pas dans dict lui-même, mais cette méthode doit être implémentée dans la sous-classe dérivée. Cela peut être facilement vérifié :

>>> 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;
En même temps, nous pouvons faire d'autres expériences, définir une sous-classe Missing et implémenter la méthode __missing__() :

>>> class Missing(dict):
...     def __missing__(self, key):
...         return 'missing'
...
>>> d = Missing()
>>> d
{}
>>> d['foo']
'missing'
>>> d
{}
Renvoyer le résultat réflexion La méthode __missing__() fait son travail. Sur cette base, nous modifions légèrement la méthode __missing__() pour que cette sous-classe définisse une valeur par défaut pour les clés inexistantes comme la classe defautldict :

>>> 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;}
Implémenter defaultdict dans les anciennes versions de Python La fonction defaultdict a été ajoutée après la version 2.5 et n'est pas prise en charge dans certaines anciennes versions. Il est donc nécessaire d'implémenter une classe defaultdict compatible pour les anciennes versions. C'est en fait très simple. Bien que les performances ne soient pas aussi bonnes que celles de la classe par défaut fournie avec la version 2.5, elles sont fonctionnellement les mêmes.

Tout d'abord, la méthode __getitem__() doit appeler la méthode __missing__() lorsque la clé d'accès échoue :

Deuxièmement, la méthode
class defaultdict(dict):
    def __getitem__(self, key):
        try:
            return dict.__getitem__(self, key)
        except KeyError:
            return self.__missing__(key)
doit être implémentée pour définir la valeur par défaut value :

__missing__()

Ensuite, la fonction d'initialisation de la classe defaultdict
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
doit accepter les paramètres de type ou de fonction appelable :

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

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Cet article est reproduit dans:. en cas de violation, veuillez contacter admin@php.cn Supprimer