"pprint" --- 数据美化输出
*************************

**源代码：** Lib/pprint.py

======================================================================

"pprint" 模块提供了“美化打印”任意 Python 数据结构的功能，这种美化形式
可用作对解释器的输入。 如果经格式化的结构包含非基本 Python 类型的对象
，则其美化形式可能无法被加载。 包含文件、套接字或类对象，以及许多其他
不能用 Python 字面值来表示的对象都有可能导致这样的结果。

格式化后的形式会在可能的情况下以单行来表示对象，并在无法在允许宽度内容
纳对象的情况下将其分为多行。 如果你需要调整宽度限制则应显式地构造
"PrettyPrinter" 对象。

字典在计算其显示形式前会先根据键来排序。

3.9 版更變: 添加了对美化打印 "types.SimpleNamespace" 的支持。

"pprint" 模块定义了一个类：

class pprint.PrettyPrinter(indent=1, width=80, depth=None, stream=None, *, compact=False, sort_dicts=True)

   构造一个 "PrettyPrinter" 实例。 此构造器接受几个关键字形参。 使用
   *stream* 关键字可设置输出流；流对象使用的唯一方法是文件协议的
   "write()" 方法。 如果未指定此关键字，则 "PrettyPrinter" 会选择
   "sys.stdout"。 每个递归层次的缩进量由 *indent* 指定；默认值为一。
   其他值可导致输出看起来有些怪异，，但可使得嵌套结构更易区分。 可被打
   印的层级数量由 *depth* 控制；如果数据结构的层级被打印得过深，其所包
   含的下一层级会被替换为 "..."。 在默认情况下，对被格式化对象的层级深
   度没有限制。 希望的输出宽度可使用 *width* 形参来限制；默认值为 80
   个字符。 如果一个结构无法在限定宽度内被格式化，则将做到尽可能接近。
   如果 *compact* 为假值（默认）则长序列的每一项将被格式化为单独的行。
   如果 *compact* 为真值，则将在 *width* 可容纳的的情况下把尽可能多的
   项放入每个输出行。 如果 *sort_dicts* 为真值（默认），字典将被格式化
   为按键排序，否则将按插入顺序显示。

   3.4 版更變: 增加了 *compact* 形参。

   3.8 版更變: 增加了 *sort_dicts* 形参。

   >>> import pprint
   >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
   >>> stuff.insert(0, stuff[:])
   >>> pp = pprint.PrettyPrinter(indent=4)
   >>> pp.pprint(stuff)
   [   ['spam', 'eggs', 'lumberjack', 'knights', 'ni'],
       'spam',
       'eggs',
       'lumberjack',
       'knights',
       'ni']
   >>> pp = pprint.PrettyPrinter(width=41, compact=True)
   >>> pp.pprint(stuff)
   [['spam', 'eggs', 'lumberjack',
     'knights', 'ni'],
    'spam', 'eggs', 'lumberjack', 'knights',
    'ni']
   >>> tup = ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead',
   ... ('parrot', ('fresh fruit',))))))))
   >>> pp = pprint.PrettyPrinter(depth=6)
   >>> pp.pprint(tup)
   ('spam', ('eggs', ('lumberjack', ('knights', ('ni', ('dead', (...)))))))

"pprint" 模块还提供了一些快捷函数：

pprint.pformat(object, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True)

   *object* 的格式化表示作为字符串返回。 *indent*, *width*, *depth*,
   *compact* 和 *sort_dicts* 将作为格式化形参被传入 "PrettyPrinter" 构
   造器。

   3.4 版更變: 增加了 *compact* 形参。

   3.8 版更變: 增加了 *sort_dicts* 形参。

pprint.pp(object, *args, sort_dicts=False, **kwargs)

   打印 *object* 的格式化表示并附带一个换行符。 如果 *sort_dicts* 为假
   值（默认），字典将按键的插入顺序显示，否则将按字典键排序。 *args*
   和 *kwargs* 将作为格式化形参被传给 "pprint()"。

   3.8 版新加入.

pprint.pprint(object, stream=None, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True)

   在 *stream* 上打打印 *object* 的格式化表示，并附带一个换行符。 如果
   *stream* 为 "None"，则使用 "sys.stdout"。 这可以替代 "print()" 函数
   在交互式解释器中使用以查看值（你甚至可以执行重新赋值 "print =
   pprint.pprint" 以在特定作用域中使用）。 *indent*, *width*, *depth*,
   *compact* 和 *sort_dicts* 将作为格式化形参被传给 "PrettyPrinter" 构
   造器。

   3.4 版更變: 增加了 *compact* 形参。

   3.8 版更變: 增加了 *sort_dicts* 形参。

   >>> import pprint
   >>> stuff = ['spam', 'eggs', 'lumberjack', 'knights', 'ni']
   >>> stuff.insert(0, stuff)
   >>> pprint.pprint(stuff)
   [<Recursion on list with id=...>,
    'spam',
    'eggs',
    'lumberjack',
    'knights',
    'ni']

pprint.isreadable(object)

   确定 *object* 的格式化表示是否“可读”，或是否可被用来通过 "eval()"
   重新构建对象的值。 此函数对于递归对象总是返回 "False"。

   >>> pprint.isreadable(stuff)
   False

pprint.isrecursive(object)

   确定 *object* 是否需要递归表示。

此外还定义了一个支持函数：

pprint.saferepr(object)

   返回 *object* 的字符串表示，并为递归数据结构提供保护。 如果
   *object* 的表示形式公开了一个递归条目，该递归引用会被表示为
   "<Recursion on typename with id=number>"。 该表示因而不会进行其它格
   式化。

   >>> pprint.saferepr(stuff)
   "[<Recursion on list with id=...>, 'spam', 'eggs', 'lumberjack', 'knights', 'ni']"


PrettyPrinter 对象
==================

"PrettyPrinter" 的实例具有下列方法：

PrettyPrinter.pformat(object)

   返回 *object* 格式化表示。 这会将传给 "PrettyPrinter" 构造器的选项
   纳入考虑。

PrettyPrinter.pprint(object)

   在所配置的流上打印 *object* 的格式化表示，并附加一个换行符。

下列方法提供了与同名函数相对应的实现。 在实例上使用这些方法效率会更高
一些，因为不需要创建新的 "PrettyPrinter" 对象。

PrettyPrinter.isreadable(object)

   确定对象的格式化表示是否“可读”，或者是否可使用 "eval()" 重建对象值
   。 请注意此方法对于递归对象将返回 "False"。 如果设置了
   "PrettyPrinter" 的 *depth* 形参并且对象深度超出允许范围，此方法将返
   回 "False"。

PrettyPrinter.isrecursive(object)

   确定对象是否需要递归表示。

此方法作为一个钩子提供，允许子类修改将对象转换为字符串的方式。 默认实
现使用 "saferepr()" 实现的内部方式。

PrettyPrinter.format(object, context, maxlevels, level)

   返回三个值：字符串形式的 *object* 已格式化版本，指明结果是否可读的
   旗标，以及指明是否检测到递归的旗标。 第一个参数是要表示的对象。 第
   二个是以对象 "id()" 为键的字典，这些对象是当前表示上下文的一部分（
   影响 *object* 表示的直接和间接容器）；如果需要呈现一个已经在
   *context* 中表示的对象，则第三个返回值应当为 "True"。 对 "format()"
   方法的递归调用应当将容器的附加条目添加到此字典中。 第三个参数
   *maxlevels* 给出了对递归的请求限制；如果没有请求限制则其值将为 "0"
   。 此参数应当不加修改地传给递归调用。 第四个参数 *level* 给出于当前
   层级；传给递归调用的参数值应当小于当前调用的值。


示例
====

为了演示 "pprint()" 函数及其形参的几种用法，让我们从 PyPI 获取关于某个
项目的信息:

   >>> import json
   >>> import pprint
   >>> from urllib.request import urlopen
   >>> with urlopen('https://pypi.org/pypi/sampleproject/json') as resp:
   ...     project_info = json.load(resp)['info']

"pprint()" 以其基本形式显示了整个对象:

   >>> pprint.pprint(project_info)
   {'author': 'The Python Packaging Authority',
    'author_email': 'pypa-dev@googlegroups.com',
    'bugtrack_url': None,
    'classifiers': ['Development Status :: 3 - Alpha',
                    'Intended Audience :: Developers',
                    'License :: OSI Approved :: MIT License',
                    'Programming Language :: Python :: 2',
                    'Programming Language :: Python :: 2.6',
                    'Programming Language :: Python :: 2.7',
                    'Programming Language :: Python :: 3',
                    'Programming Language :: Python :: 3.2',
                    'Programming Language :: Python :: 3.3',
                    'Programming Language :: Python :: 3.4',
                    'Topic :: Software Development :: Build Tools'],
    'description': 'A sample Python project\n'
                   '=======================\n'
                   '\n'
                   'This is the description file for the project.\n'
                   '\n'
                   'The file should use UTF-8 encoding and be written using '
                   'ReStructured Text. It\n'
                   'will be used to generate the project webpage on PyPI, and '
                   'should be written for\n'
                   'that purpose.\n'
                   '\n'
                   'Typical contents for this file would include an overview of '
                   'the project, basic\n'
                   'usage examples, etc. Generally, including the project '
                   'changelog in here is not\n'
                   'a good idea, although a simple "What\'s New" section for the '
                   'most recent version\n'
                   'may be appropriate.',
    'description_content_type': None,
    'docs_url': None,
    'download_url': 'UNKNOWN',
    'downloads': {'last_day': -1, 'last_month': -1, 'last_week': -1},
    'home_page': 'https://github.com/pypa/sampleproject',
    'keywords': 'sample setuptools development',
    'license': 'MIT',
    'maintainer': None,
    'maintainer_email': None,
    'name': 'sampleproject',
    'package_url': 'https://pypi.org/project/sampleproject/',
    'platform': 'UNKNOWN',
    'project_url': 'https://pypi.org/project/sampleproject/',
    'project_urls': {'Download': 'UNKNOWN',
                     'Homepage': 'https://github.com/pypa/sampleproject'},
    'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
    'requires_dist': None,
    'requires_python': None,
    'summary': 'A sample Python project',
    'version': '1.2.0'}

结果可以被限制到特定的 *depth* (更深层的内容将使用省略号):

   >>> pprint.pprint(project_info, depth=1)
   {'author': 'The Python Packaging Authority',
    'author_email': 'pypa-dev@googlegroups.com',
    'bugtrack_url': None,
    'classifiers': [...],
    'description': 'A sample Python project\n'
                   '=======================\n'
                   '\n'
                   'This is the description file for the project.\n'
                   '\n'
                   'The file should use UTF-8 encoding and be written using '
                   'ReStructured Text. It\n'
                   'will be used to generate the project webpage on PyPI, and '
                   'should be written for\n'
                   'that purpose.\n'
                   '\n'
                   'Typical contents for this file would include an overview of '
                   'the project, basic\n'
                   'usage examples, etc. Generally, including the project '
                   'changelog in here is not\n'
                   'a good idea, although a simple "What\'s New" section for the '
                   'most recent version\n'
                   'may be appropriate.',
    'description_content_type': None,
    'docs_url': None,
    'download_url': 'UNKNOWN',
    'downloads': {...},
    'home_page': 'https://github.com/pypa/sampleproject',
    'keywords': 'sample setuptools development',
    'license': 'MIT',
    'maintainer': None,
    'maintainer_email': None,
    'name': 'sampleproject',
    'package_url': 'https://pypi.org/project/sampleproject/',
    'platform': 'UNKNOWN',
    'project_url': 'https://pypi.org/project/sampleproject/',
    'project_urls': {...},
    'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
    'requires_dist': None,
    'requires_python': None,
    'summary': 'A sample Python project',
    'version': '1.2.0'}

此外，还可以设置建议的最大字符 *width*。 如果一个对象无法被拆分，则将
超出指定宽度:

   >>> pprint.pprint(project_info, depth=1, width=60)
   {'author': 'The Python Packaging Authority',
    'author_email': 'pypa-dev@googlegroups.com',
    'bugtrack_url': None,
    'classifiers': [...],
    'description': 'A sample Python project\n'
                   '=======================\n'
                   '\n'
                   'This is the description file for the '
                   'project.\n'
                   '\n'
                   'The file should use UTF-8 encoding and be '
                   'written using ReStructured Text. It\n'
                   'will be used to generate the project '
                   'webpage on PyPI, and should be written '
                   'for\n'
                   'that purpose.\n'
                   '\n'
                   'Typical contents for this file would '
                   'include an overview of the project, '
                   'basic\n'
                   'usage examples, etc. Generally, including '
                   'the project changelog in here is not\n'
                   'a good idea, although a simple "What\'s '
                   'New" section for the most recent version\n'
                   'may be appropriate.',
    'description_content_type': None,
    'docs_url': None,
    'download_url': 'UNKNOWN',
    'downloads': {...},
    'home_page': 'https://github.com/pypa/sampleproject',
    'keywords': 'sample setuptools development',
    'license': 'MIT',
    'maintainer': None,
    'maintainer_email': None,
    'name': 'sampleproject',
    'package_url': 'https://pypi.org/project/sampleproject/',
    'platform': 'UNKNOWN',
    'project_url': 'https://pypi.org/project/sampleproject/',
    'project_urls': {...},
    'release_url': 'https://pypi.org/project/sampleproject/1.2.0/',
    'requires_dist': None,
    'requires_python': None,
    'summary': 'A sample Python project',
    'version': '1.2.0'}
