2017-07-10 81 views
0

我需要驗證'信息'是JSON文件或Python字典。鑑於json文件和python dict具有相同的結構這一事實,我編寫了此代碼來解析它們並將它們的內容保存在一個變量中,但我認爲這是一個pythonic和更高效的代碼。Pythonic的方式來驗證是否JSON或Python字典

import json 

class LoadInfo(object): 
def __init__(self, info=None): 
    if info: 
     try: 
      self.config= json.loads(info) 
     except ValueError: 
      print('Load Python Dict') 
      try: 
       if isinstance(info, dict): 
        self.config= info 
      except ValueError: 
       print('Json or python dict config is needed') 
    else: 
     raise Exception('Json or python dict config is needed') 

info = LoadInfo('path/to/json_file') #should work 
info_dict = dict('A'=1, 'B'=2, 'C'=3) 
info2 = LoadInfo(info_dict) #Also should work 

任何人有更多的想法?

+1

IMO你應該調整你的代碼。爲什麼不能簡單地將數據加載到'LoadInfo'類之外並將結果傳遞給它?爲什麼'LoadInfo'應該在一個參數下接受兩種不同的類型? – freakish

+4

爲什麼要編寫一個需要字典或JSON字符串的代碼?我會寫一個classmethod'def from_json(cls,info):return cls(json.loads(info))'。這樣你只能處理'__init__'中的字典案例。你也不應該只是'拋出異常:';如果需要'info'參數,*不要給它一個默認值*。 – jonrsharpe

回答

4

首先第一件事,不只是raise Exception;這太籠統了,儘可能詳細地描述出了什麼問題。在這種情況下,用戶沒有提供info參數。兩個問題是:

  1. 你應該通過身份測試None,不感實性(否則例如{}將是一個例外,這可能不是你真正想要的東西):if info is not None:

  2. 如果這是一個必需的參數,爲什麼給它一個默認值?

修訂1:

import json 

class LoadInfo(object): 

    def __init__(self, info): 
     try: 
      self.config = json.loads(info) 
     except ValueError: 
      print('Load Python Dict') 
      try: 
       if isinstance(info, dict): 
        self.config = info 
      except ValueError: 
       print('python dict config is needed') 

(注輕微style guide調整。)


接下來,真的沒有必要通過允許提供這種多態性無論是字典或JSON字符串作爲參數。在第二種情況下,您只是將它解析爲第一種情況,那麼請創建一個類方法,這是Python中常見的替代構造函數模式。

修訂2:

import json 

class LoadInfo(object): 

    def __init__(self, info): 
     try: 
      if isinstance(info, dict): 
       self.config = info 
     except ValueError: 
      print('python dict config is needed') 

    @classmethod 
    def from_json(cls, info): 
     return cls(json.loads(info)) 

其中的一部分:

if isinstance(info, dict): 
    self.config = info 

你希望提出一個ValueError?爲什麼呢,如果它不是一種可以接受的輸入類型,你想只是print的東西,讓程序繼續?請注意,如果您正在檢查類型,最好使用ABCs

修訂3:

from collections.abc import Mapping 
import json 

class LoadInfo(object): 

    def __init__(self, info): 
     if not isinstance(info, Mapping): 
      raise TypeError('mapping config is needed') 
     self.config = info 

    @classmethod 
    def from_json(cls, info): 
     return cls(json.loads(info)) 

但實際上,你所建議的,它可以從一個文件,而不是JSON字符串作爲當前的代碼加載意味着(你提供'path/to/json_file''{"foo": "bar"}' - 這不是清楚你所期望的json.loads)。所以你需要處理該文件。

修訂4:

from collections.abc import Mapping 
import json 

class LoadInfo(object): 

    def __init__(self, info): 
     if not isinstance(info, Mapping): 
      raise TypeError('mapping config is needed') 
     self.config = info 

    @classmethod 
    def from_json_file(cls, filename): 
     with open(filename) as json_file: 
      return cls(json.load(json_file)) # note 'load' not 'loads' 

現在你的例子變成:

info = LoadInfo.from_json_file('path/to/json_file') 
info_dict = dict(A=1, B=2, C=3) # note you shouldn't use quotes for keys here 
info2 = LoadInfo(info_dict) 
-1

您需要首先打開一個文件對象,如果你通過一個文件,它會是更好的單獨的文件和字符串參數:

import os 
import json 

class LoadInfo(object): 
    def __init__(self, info=None, file=None): 
     if file and os.path.exists(file): 
      with open(file) as f: 
       data = f.read() 
      try: 
       self.config = json.loads(data) 
      except ValueError: 
       raise ValueError('Load JSON file error') 
     elif info: 
      if isinstance(info, dict): 
       self.config = info 
      elif isinstance(info, str): 
       try: 
        self.config = json.loads(info) 
       except ValueError: 
        raise ValueError('Load JSON string error') 
     else: 
      raise ValueError('Load config error') 

我將它拆分成兩個方法:

class LoadInfo(object): 
    def load_from_file(self, file): 
     with open(file) as f: 
      data = f.read() 
     self.config = json.loads(data) 

    def load_from_str(self, info): 
     if isinstance(info, dict): 
      self.config = info 
     elif isinstance(info, str): 
      self.config = json.loads(info) 
     else: 
      raise ValueError('Load config error') 

但實際上,使用ducktyping風格更pythonic。

相關問題