为了对付表单提交时参数多和 json 结构复杂的状况,我写了一个名为 recursive_json_loads
的处理函数来对请求对象递归调用 json.loads()
以期可以一次性将全部参数转化为更好用的 Python 类型。后来又发现了 web.py 的 Storage
对象,使这个函数愈加好用起来。python
lang:python import simplejson as json def recursive_json_loads(data): if isinstance(data, list): return [recursive_json_loads(i) for i in data] elif isinstance(data, tuple): return tuple([recursive_json_loads(i) for i in data]) elif isinstance(data, dict): return Storage({recursive_json_loads(k): recursive_json_loads(data[k]) for k in data.keys()}) else: try: obj = json.loads(data) if obj == data: return data except: return data return recursive_json_loads(obj) class Storage(dict): """ A Storage object is like a dictionary except `obj.foo` can be used in addition to `obj['foo']`. >>> o = storage(a=1) >>> o.a 1 >>> o['a'] 1 >>> o.a = 2 >>> o['a'] 2 >>> del o.a >>> o.a Traceback (most recent call last): ... AttributeError: 'a' """ def __getattr__(self, key): try: return self[key] except KeyError as k: raise AttributeError(k) def __setattr__(self, key, value): self[key] = value def __delattr__(self, key): try: del self[key] except KeyError as k: raise AttributeError(k) def __repr__(self): return '<Storage ' + dict.__repr__(self) + '>'
用法以下:web
lang:python >>> request = json.dumps({"foo":["a", 123], "bar": {1:"int", "str":"05"}}) >>> data = recursive_json_loads(request) >>> data.foo ['a', 123] >>> data.bar <Storage {1: 'int', 'str': '05'}> >>> data.bar.str '05' >>> data.bar[1] 'int'
至因而否应该把 Storage 的 self[key]
改为 self.get(k)
,从而避免在访问不存在的值时触发属性异常。想了一下感受不大好,主要是并无把参数检查的代码简化多少。json
说到参数检查,通常能够作三步:函数
有一点须要注意的是,对于传了参数而没有传值的状况(?k=),k 的值会是 ''
,并且 isinstance('', str)
会返回 True。code
对于必须参数,一般第二和第三步是一块儿完成的,好比:对象
lang:python if not hasattr(data, 'k') or not isinstance(data.k, int): return error()
但非必须参数就要单独考虑第二种状况了,由于第二种也是合法的:递归
lang:python if hasattr(data, 'k') and data.k != '' and not isinstance(data.k, int): return error()
由于 Python 会把不少种如 len()
为零的对象的布尔值判断为 False
,因此上面始终没有使用 if data.k:
这样的写法,以免误判。get
补充,Storage 类的一个缺点是:他有 __dict__
属性,但该属性永远为空it