爲了對付表單提交時參數多和 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