我需要验证'info'是json文件还是python dict。鉴于json文件和python dict具有相同的结构,我编写了这个代码来解析它们并将它们的内容保存在变量中,但我认为有一个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
任何人都有更多的想法?
答案 0 :(得分:4)
首先,不要只是raise Exception
;这太普遍了,对于出了什么问题,尽可能具体。在这种情况下,用户没有提供info
参数。两个问题:
您应该通过身份测试None
,而不是真实性(否则,例如{}
将是一个例外,这可能不是您真正想要的):if info is not None:
。< / p>
如果它是必需参数,为什么要给它一个默认值?!
修订版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 :(得分:-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。