Python 的完美 json loads

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


說到參數檢查,通常能夠作三步:函數

  1. 是否傳了某個參數 (?k)
  2. 參數值是否爲空 (?k=)
  3. 參數的類型/值是否符合要求(?k=0)

有一點須要注意的是,對於傳了參數而沒有傳值的狀況(?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

相關文章
相關標籤/搜索