Python-Flaskソースコードの詳細研究:flask_EncoderにおけるJSONEncoder(object)クラス

7599 ワード

編集者はpython-flaskフレームワークのバックエンドの開発に従事して、それを食べるために、編集者は絶えずソースコードを深く研究して、今日flask_EncoderではJSONEncoder(object)クラスが深く研究を開始している.
class JSONEncoder(object):
    """   JSON   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)

class Decimal(object):
    def __float__(self):
        if self.isnan():
            if self.is_nan():
                raise ValueError("Cannot convert signaling NaN to float")
            s = "-nan" if self._sign else "nan"
        else:
            s = str(self)
        return float(s)


    def _isnan(self):
        """       0
        0 if a number
        1 if NaN
        2 if sNaN
        """
        if self._is_sepcial:
            exp = self._exp
            if exp == 'n':
                return 1
            elif exp == 'N':
                return 2
        return 0

    def isnan(self):
        """   NaN,  True,   ,  False"""
        return self._exp == 'N'