1. 程式人生 > >深入研究Python-Flask原始碼:flask_encoder中JSONEncoder(object)類

深入研究Python-Flask原始碼:flask_encoder中JSONEncoder(object)類

小編從事python-flask框架的後端開發,為了吃透它,小編會不斷的深入研究原始碼,今天從 flask_encoder中JSONEncoder(object)類開始深入研究。

class JSONEncoder(object):
    """可擴充套件JSON <http://json.org>編碼Python資料結構。
    預設支援以下物件和型別:
    +-------------------+---------------+
    | Python            | JSON          |
    +===================+===============+
    | dict              | object        |
    +-------------------+---------------+
    | list, tuple       | array         |
    +-------------------+---------------+
    | str               | string        |
    +-------------------+---------------+
    | int, float        | number        |
    +-------------------+---------------+
    | True              | true          |
    +-------------------+---------------+
    | False             | false         |
    +-------------------+---------------+
    | None              | null          |
    +-------------------+---------------+

    
    要擴充套件它以識別其他物件,可以使用子類和實現a''.default()方法,以及返回可序列化的另一個方法
    物件“o”,如果可能,它應該呼叫超類實現(丟擲'TypeError')。
    """
    
    def __init__(self, *, skipkeys=False, ensure_ascii=True,check_circular=True, allow_nan=True, sort_keys=False,indent=None, separators=None, default=None):

        """如果skipkeys為false,那麼嘗試它就是一個型別錯誤對不是str、int、float或None的鍵進行編碼。如果skipkeys是正確的,這樣的專案只是跳過。

        如果ensure_ascii為真,則輸出保證為str物件,所有傳入的非ascii字元都轉義。
如果ensure_ascii為false,則輸出可以包含非ascii字元。
        
        如果check_circular為true,那麼在編碼期間,將檢查列表、dicts和自定義編碼物件,以查詢迴圈引用,以防止無限遞迴(這會導致溢位錯誤)。
否則,不會進行此類檢查。

        如果allow_nan為真,那麼NaN、∞和-∞就會被編碼成這樣。這種行為不符合JSON規範,但與大多數基於JavaScript的編碼器和解碼器是一致的。否則,編碼這樣的浮點數將是一個ValueError。
        
        如果sort_keys為真,那麼字典的輸出將按鍵排序;這對於迴歸測試非常有用,可以確保每天都可以比較JSON序列化。

        如果indent是一個非負整數,那麼JSON陣列元素和物件成員將用縮排級別漂亮地打印出來。縮排級別為0只會插入換行符。沒有一個是最緊湊的表示。

        如果specified,分隔符應該是(item_separator, key_separator)元組。預設值是(',',':').如果indent is None 和(',',':')。要獲得最簡潔的JSON表示,您應該指定(',',':')以消除空白。

        如果指定了預設值,則預設值是一個函式,用於呼叫無法序列化的物件。它應該返回一個JSON可編碼版本的物件,或者引發一個“型別錯誤”。

        """初始化
        self.skipkeys = skipkeys
        self.ensure_ascii = ensure_ascii
        self.check_circular = check_circular
        self.allow_nan = allow_nan
        self.sort_keys = sort_keys
        self.indent = indent
        if separators is not None:
            self.item_separator, self.key_separator = separators
        elif indent is not None:
            self.item_separator = ','
        if default is not None:
            self.default = default

    def default(self, o):
        """在子類中實現此方法,使其返回可序列化的物件'o',或呼叫基本實現(引發'TypeError')。
例如,要支援任意迭代器,可以這樣做實現預設如下::
            def default(self, o):
                try:
                    iterable = iter(o)
                except TypeError:
                    pass
                else:
                    return list(iterable)
                # 讓基類預設方法引發型別錯誤
                return JSONEncoder.default(self, o)

        """
        raise TypeError("Object of type '%s' is not JSON serializable" %
                        o.__class__.__name__)

    def encode(self, o):
        """返回Python資料結構的JSON字串表示形式.
        >>> from json.encoder import JSONEncoder
        >>> JSONEncoder().encode({"foo": ["bar", "baz"]})'{"foo": ["bar", "baz"]}'
        """
       # 這是非常簡單的案例和基準測試。
        if isinstance(o, str):
            if self.ensure_ascii:
                return encode_basestring_ascii(o)
            else:
                return encode_basestring(o)
        # 這不會將迭代器直接傳遞到" .join(),因為異常沒有那麼詳細。列表呼叫應該是大致與.join()            
        # 所做的PySequence_Fast等價。
        chunks = self.iterencode(o, _one_shot=True)
        if not isinstance(chunks, (list, tuple)):
            chunks = list(chunks)
        return ''.join(chunks)
    def iterencode(self, o, _one_shot=False):
        """對給定物件進行編碼併產生每個字串,表示是可用的。
        demo::
            for chunk in JSONEncoder().iterencode(bigobject):
                mysocket.write(chunk)
        """
        if self.check_circular:
            markers = {}
        else:
            markers = None
        if self.ensure_ascii:
            _encoder = encode_basestring_ascii
        else:
            _encoder = encode_basestring

        def floatstr(o, allow_nan=self.allow_nan,
                _repr=float.__repr__, _inf=INFINITY, _neginf=-INFINITY):
            # Check for specials.  Note that this type of test is processor
            # and/or platform-specific, so do tests which don't depend on the
            # internals.

            if o != o:
                text = 'NaN'
            elif o == _inf:
                text = 'Infinity'
            elif o == _neginf:
                text = '-Infinity'
            else:
                return _repr(o)

            if not allow_nan:
                raise ValueError("Out of range float values are not JSON compliant: " + repr(o))
            return text
        if (_one_shot and c_make_encoder is not None and self.indent is None):
            _iterencode = c_make_encoder(markers, self.default, _encoder, self.indent,
                self.key_separator, self.item_separator, self.sort_keys,
                self.skipkeys, self.allow_nan)
        else:
            _iterencode = _make_iterencode(markers, self.default, _encoder, self.indent, floatstr,self.key_separator, self.item_separator, self.sort_keys,self.skipkeys,_one_shot)
        return _iterencode(o, 0)

小編髮現,原始碼對於json的打包有預設的資料型別,但是,我們可以給他擴充套件其他型別,比如:decimal。

class JSONEncoder(_json.JSONEncoder):
    """預設的Flask JSON編碼器。這個版本擴充套件了預設的simplejson編碼器,支援“datetime”物件、“UUID”物件和“Markup”物件,這些物件被序列化為RFC 822 datetime字串(與HTTP日期格式相同)。為了支援更多的資料型別,請重寫:meth: ' default '方法。
    """

    def default(self, o):
        """在子類中實現此方法,使其返回可序列化的物件'o',或呼叫基本實現(引發'TypeError ')。
        例如,要支援任意迭代器,可以這樣實現預設值::
            def default(self, o):
                try:
                    iterable = iter(o)
                except TypeError:
                    pass
                else:
                    return list(iterable)
                return JSONEncoder.default(self, o)
        """
        if isinstance(o, datetime):
            return http_date(o)
        if isinstance(o, uuid.UUID):
            return str(o)
        if hasattr(o, '__html__'):
            return text_type(o.__html__())
        if isinstance(o, Decimal):
            return o.__float__()
        return _json.JSONEncoder.default(self, o)