我需要验证'info'是json文件还是python字典。鉴于 json 文件和 python 字典具有相同的结构,我编写了这段代码来解析两者并将其内容保存在变量中,但我认为有一个 pythonic 和更有效的代码。
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
有人有更多的思想吗?
首先,不要只raise Exception
; 这太笼统了,尽可能具体地说明出了什么问题。在这种情况下,用户尚未提供info
参数。这样做有两个问题:
-
您应该通过身份而不是真实性来测试
None
(否则例如{}
将是一个例外,这可能不是您真正想要的(:if info is not None:
. -
如果它是必需参数,为什么要给它一个默认值?!
修订版 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')
(请注意细微的风格指南调整。
接下来,实际上没有必要通过允许字典或 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
一些东西,让程序继续?请注意,在检查类型时,最好使用 ABC。
修订版 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)
如果你传递一个文件,你需要首先打开一个文件对象,最好将文件和字符串参数分开:
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')
但实际上,使用鸭子打字风格更蟒蛇。