2014-09-01 2 views
0

Je travaille donc avec une API qui renvoie un JSON après l'envoi d'une requête. J'ai écrit une classe wrapper autour de cette réponse JSON afin que je puisse gérer n'importe quel changement dans le JSON en un seul endroit. Cela aide aussi que je puisse accéder facilement aux valeurs maintenant.Gestion de la réponse json variable

Voici l'emballage je l'ai écrit:

class WitResponse: 
    def __init__(self, json_string): 
     self.json_string = json_string 
     self.wit_response = json.loads(json_string) 

    @property 
    def intent(self): 
     return self.wit_response["outcomes"][0]["intent"] 

    @property 
    def confidence(self): 
     return self.wit_response["outcomes"][0]["confidence"] 

    @property 
    def text(self): 
     return self.wit_response["_text"] 

    @property 
    def entites(self): 
     return self.wit_response["outcomes"][0]["entites"] 

    @property 
    def msg_id(self): 
     return self.wit_response["msg_id"] 

    @property 
    def response(self): 
     return self.json_string.translate(None,"\n")+"\n" #Saves the reply in an already easy to send format 

    @property 
    def target(self): 
     return self.wit_response["outcomes"][0]["entities"]["target"][0]["value"] 

Un exemple d'une clé très fréquente qui se trouve dans le JSON est la clé target (comme on peut le voir ci-dessus). Comme il n'existe pas toujours, appeler la méthode target déclenchera une exception. Je suis à la recherche d'une solution pour gérer des domaines comme celui-ci qui seront aussi élégants que possible.

Au moment que je viens Enveloppez la la déclaration de retour dans la méthode target avec un essai, sauf bloc et renvoie None si une exception est levée (JSON n'a pas une clé target).

J'ai aussi pensé à utiliser un décorateur qui ajoute l'essai, sauf le bloc mais il ne semble pas fonctionner quand j'ai ajouté le décorateur au-dessus du décorateur @property:

def None_Return_Value_Decorator(func): 
    def wrapper(self): 
     try: 
      value = func(self) 
      return value 
     except: 
      return None 

    return wrapper 

Y at-il des solutions plus élégantes ? Si non, le décorateur peut-il fonctionner (et comment le réparer si c'est le cas)?

Répondre

2

Ajoutez votre décorateur ci-dessous le @property décorateur:

@property 
@None_Return_Value_Decorator 
def target(self): 
    return self.wit_response["outcomes"][0]["entities"]["target"][0]["value"] 

Maintenant, votre décorateur est appliqué d'abord, avant de mettre la valeur de retour de votre décorateur dans le getter de la propriété.

Toutefois, vous souhaitez avoid using a except handler; essayez d'attraper uniquement une exception pertinente, telle que IndexError et KeyError.

Vous pouvez faire des exceptions configurables dans le décorateur:

from functools import wraps 

def ignore_exception(*exceptions): 
    def decorator(f): 
     @wraps(f) 
     def wrapper(*args, **kw): 
      try: 
       return f(*args, **kw) 
      except exceptions: 
       return None 
     return wrapper 
    return decorator 

utilisent alors comme:

@property 
@ignore_exception(KeyError) 
def target(self): 
    return self.wit_response["outcomes"][0]["entities"]["target"][0]["value"] 

par exemple.

+0

Cela semble fonctionner. Etes-vous conscient d'une meilleure façon de gérer cela que j'ai déjà? Cela me semble très inélégant. – Shookie

+0

@Shookie: si vous utilisez Python 3.4, vous pouvez utiliser le nouveau gestionnaire de contexte ['contextlib.suppress()'] (https://docs.python.org/3/library/contextlib.html#contextlib.suppress). –

+0

@Shookie: mais en utilisant un décorateur pour encapsuler la manipulation commune me semble bien; vous pourriez faire en sorte que le décorateur accepte l'exception (s) à attraper en tant qu'argument même. –