[PYTHON] Créez un defaultdict qui renvoie un defaultdict pour créer un monde où KeyErrror ne se produit pas (+ exemple d'analyse JSON)

La plupart des choses que tout le monde aime «collections» sont préparées et intéressantes.

Créez un defaultdict qui renvoie un defaultdict pour créer un monde où Key Errror ne se produit pas

defaultdict est une classe d'extension de dict qui peut définir le comportement lorsque la clé n'est pas trouvée.

8.3. Collections - Types de données de conteneurs hautes performances - Documentation Python 2.7ja1

Il est très pratique de l'utiliser pour le traitement d'agrégation, etc., car il n'est pas nécessaire de classer le comportement en fonction de la présence ou de l'absence de la clé. Ceci est une réimpression de l'exemple d'utilisation, mais c'est probablement le plus simple à comprendre.

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

Il existe un exemple d'utilisation comme compteur, mais si vous souhaitez l'utiliser comme simple compteur, il est recommandé de considérer collections.Counter [^ counter].

[^ counter]: 8.3. collections - Type de données de conteneur hautes performances - Documentation Python 2.7ja1

Utilisé dans les dictionnaires imbriqués

Par exemple, si vous appelez d ['a'] ['b'] ['c'] dans un dictionnaire imbriqué, même si d est defaultdict,d ['a'] Si la valeur de «est le dict normal», alors «Key Errror» peut se produire. Par conséquent, essayez ce qui suit pour ladefault_factory transmise à la defaultdict`.

def _factory():
    return collections.defaultdict(_factory)

Avec cela, nous avons un monde où KeyErrror ne se produit pas: accept:.

>>> import collections
>>> def _factory():
...     return collections.defaultdict(_factory)
... 
>>> d = collections.defaultdict(_factory)
>>> d['a']
defaultdict(<function _factory at 0x105e93aa0>, {})
>>> d['a']['b']
defaultdict(<function _factory at 0x105e93aa0>, {})
>>> d['a']['b'][1]
defaultdict(<function _factory at 0x105e93aa0>, {})
>>> d[1][1][0][1][1][1][1][1]
defaultdict(<function _factory at 0x105e93aa0>, {})

Exemple d'utilisation de JSON dans l'analyse

Appliquons l'exemple ci-dessus à un exemple d'utilisation dans le monde réel. Ce qui suit n'est qu'une idée, il peut donc y avoir un moyen plus propre de faciliter les choses. S'il te plaît dis moi si tu sais.

Par exemple, supposons que vous ayez les informations de cours JSON suivantes pour les cours en ligne. Je n'aime pas le lieu de «adresse». Il peut y avoir ou non une clé.

{  
  "class":{  
    "id":1,
    "subject":"Math",
    "students":[  
      {  
        "name":"Alice",
        "age":30
      },
      {  
        "name":"Bob",
        "age":40,
        "address":{  
          "country":"JP"
        }
      },
      {  
        "name":"Charlie",
        "age":20,
        "address":{  
          "country":"US",
          "state":"MA",
          "locality":"Boston"
        }
      }
    ]
  }
}

Lisons ceci en Python.

In [47]: j = json.loads(s)

In [54]: for student in j["class"]["students"]:
    print(student["name"])
   ....:     
Alice
Bob
Charlie

C'est correct parce que tout le monde a «nom», mais quand j'essaye d'obtenir des informations d'état parce que je veux des informations d'état, Bob n'a pas d'informations d'état et Alice n'a pas la clé «adresse» elle-même en premier lieu. Hmm.

In [55]: for student in j["class"]["students"]:
    print(student["address"]["state"])
   ....:
---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-55-69836c86e040> in <module>()
      1 for student in j["class"]["students"]:
----> 2     print(student["address"]["state"])
      3 

KeyError: 'address'

Vous pouvez spécifier la valeur par défaut en utilisant dict.get (key, default_val), mais elle sera redondante car elle est imbriquée en plusieurs étapes. À mesure que la profondeur augmente, cela devient de plus en plus difficile.

C'est donc defaultdict. json.load et json.loads ont un port appelé ʻobject_hook` qui spécifie le traitement du hook pour le dict du résultat du décodage, alors utilisons-le. Python est un langage merveilleux pour avoir une telle API. 18.2. Json - Encodeur et décodeur JSON - Documentation Python 2.7ja1

Définissez la méthode suivante

def _hook(d):
    return collections.defaultdict(_factory, d)

Passez-le à ʻobject_hook dans json.loads`.

In [75]: j2 = json.loads(s, object_hook=_hook)
In [83]: for student in j2["class"]["students"]:
   ....:     print(student["address"]["state"])
   ....:     
defaultdict(<function _factory at 0x10a57ccf8>, {})
defaultdict(<function _factory at 0x10a57ccf8>, {})
MA

L'a fait. «KeyErrror» ne se produit pas. C'est un peu difficile à utiliser tel quel, donc je vais le donner via une méthode auxiliaire de conversion. J'ai rendu possible la spécification d'une valeur alternative à utiliser, et la valeur alternative par défaut est la chaîne default_state.

In [91]: def _dd(v, alt_val="default_state"):
    return alt_val if isinstance(v, collections.defaultdict) and len(v) == 0 else v
   ....: 

In [92]: for student in j2["class"]["students"]:
    print(_dd(student["address"]["state"]))
   ....:     
default_state
default_state
MA

Vous pouvez maintenant spécifier la valeur par défaut avec une petite quantité de description, peu importe où se trouve la clé manquante. S'il s'agit en fait du dernier appel (c'est-à-dire le moment de l'appel à étudiant [" adresse "] [" état "] au lieu de étudiant [" adresse "] dans le code ci-dessus, la valeur par défaut est retournée. Je voulais, mais j'ai abandonné parce que je ne pouvais pas déterminer si c'était le dernier appel. Si vous savez comment faire, faites-le moi savoir.

c'est tout.

Recommended Posts

Créez un defaultdict qui renvoie un defaultdict pour créer un monde où KeyErrror ne se produit pas (+ exemple d'analyse JSON)
Tornado - Créons une API Web qui renvoie facilement JSON avec JSON
Un codec Python spécial qui semble savoir mais ne sait pas
Comment corriger un bug qui empêche le notebook Jupyter de démarrer automatiquement
J'ai essayé de créer une classe qui peut facilement sérialiser Json en Python
Une histoire qui parfois ne marche pas si pip est le dernier
J'ai essayé de créer une fonction de dictionnaire insensible à la casse
Comment créer un fichier JSON en Python