"pprint" --- データ出力の整然化
*******************************

**ソースコード:** Lib/pprint.py

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

"pprint" モジュールを使うと、Pythonの任意のデータ構造をインタープリタ
への入力で使われる形式にして "pretty-print" できます。書式化された構造
の中にPythonの基本的なタイプではないオブジェクトがあるなら、表示できな
いかもしれません。表示できないのは、ファイル、ソケット、あるいはクラス
のようなオブジェクトや、 その他Pythonのリテラルとして表現できない様々
なオブジェクトが含まれていた場合です。

可能であればオブジェクトを1行で整形しますが、与えられた幅に合わないな
ら複数行に分けて整形します。 出力幅を指定したい場合は、
"PrettyPrinter" オブジェクトを作成して明示してください。

辞書は表示される前にキーの順でソートされます。

バージョン 3.9 で変更: "types.SimpleNamespace" の pretty-print サポー
トが追加されました。

バージョン 3.10 で変更: "dataclasses.dataclass" の pretty-print サポー
トが追加されました。

"pprint" モジュールには1つのクラスが定義されています:

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

   "PrettyPrinter" のインスタンスを生成します。このコンストラクタには
   いくつかのキーワード引数を設定できます。

   *stream* (default "sys.stdout") is a *file-like object* to which
   the output will be written by calling its "write()" method.

   Other values configure the manner in which nesting of complex data
   structures is displayed.

   *indent* (default 1) specifies the amount of indentation added for
   each nesting level.

   *depth* controls the number of nesting levels which may be printed;
   if the data structure being printed is too deep, the next contained
   level is replaced by "...".  By default, there is no constraint on
   the depth of the objects being formatted.

   *width* (default 80) specifies the desired maximum number of
   characters per line in the output. If a structure cannot be
   formatted within the width constraint, a best effort will be made.

   *compact* impacts the way that long sequences (lists, tuples, sets,
   etc) are formatted. If *compact* is false (the default) then each
   item of a sequence will be formatted on a separate line.  If
   *compact* is true, as many items as will fit within the *width*
   will be formatted on each output line.

   If *sort_dicts* is true (the default), dictionaries will be
   formatted with their keys sorted, otherwise they will display in
   insertion order.

   If *underscore_numbers* is true, integers will be formatted with
   the "_" character for a thousands separator, otherwise underscores
   are not displayed (the default).

   バージョン 3.4 で変更: *compact* 引数が追加されました。

   バージョン 3.8 で変更: *sort_dicts* 引数が追加されました。

   バージョン 3.10 で変更: *underscore_numbers* 引数が追加されました。

   >>> 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, underscore_numbers=False)

   *object* を書式化して文字列として返します。 *indent*, *width*,
   *depth*, *compact*, *sort_dicts*, *underscore_numbers* は
   "PrettyPrinter" コンストラクタに書式化引数として渡されます。

   バージョン 3.4 で変更: *compact* 引数が追加されました。

   バージョン 3.8 で変更: *sort_dicts* 引数が追加されました。

   バージョン 3.10 で変更: *underscore_numbers* 引数が追加されました。

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

   *object* のフォーマットされた表現の後に改行を入れて表示します。もし
   *sort_dicts* が false (デフォルト) ならば、辞書はキーが挿入順に表示
   され、そうでなければ、辞書のキーがソートされます。 *args* と
   *kwargs* はフォーマットパラメータとして "pprint()" に渡されます。

   バージョン 3.8 で追加.

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

   *stream* 上に *object* の書式化された表現、続いて改行を出力します。
   *stream* が "None" の場合、 "sys.stdout" が使用されます。これは、対
   話型インタプリタの中で値を調査するために "print()"  関数の代わりに
   使用されることがあります (さらに、スコープ内で使用するために "print
   = pprint.pprint" を再代入することができます)。 *indent*, *width*,
   *depth*, *compact*, *sort_dicts*, *underscore_numbers* は、書式化引
   数として "PrettyPrinter" コンストラクタに渡されます。

   バージョン 3.4 で変更: *compact* 引数が追加されました。

   バージョン 3.8 で変更: *sort_dicts* 引数が追加されました。

   バージョン 3.10 で変更: *underscore_numbers* 引数が追加されました。

   >>> 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* を書式化して出力できる("readable") か、あるいは "eval()"
   を使って値を再構成できるかを返します。再帰的なオブジェクトに対して
   は常に "False" を返します。

   >>> pprint.isreadable(stuff)
   False

pprint.isrecursive(object)

   *object* が再帰的な表現かどうかを返します。

さらにもう1つ、関数が定義されています:

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)

   *object* を書式化して出力できる（"readable"）か、あるいは "eval()"
   を使って値を再構成できるかを返します。これは再帰的なオブジェクトに
   対して "False" を返すことに注意して下さい。もし "PrettyPrinter" の
   *depth* 引数が設定されていて、オブジェクトのレベルが設定よりも深か
   ったら、 "False" を返します。

PrettyPrinter.isrecursive(object)

   オブジェクトが再帰的な表現かどうかを返します。

このメソッドをフックとして、サブクラスがオブジェクトを文字列に変換する
方法を修正するのが可能になっています。デフォルトの実装では、内部で
"saferepr()" を呼び出しています。

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

   次の3つの値を返します。*object* をフォーマット化して文字列にしたも
   の、その結果が読み込み可能かどうかを示すフラグ、再帰が含まれている
   かどうかを示すフラグ。最初の引数は表示するオブジェクトです。 2つめ
   の引数はオブジェクトの "id()" をキーとして含むディクショナリで、オ
   ブジェクトを含んでいる現在の（直接、間接に *object* のコンテナとし
   て表示に影響を与える）環境です。ディクショナリ *context* の中でどの
   オブジェクトが表示されたか表示する必要があるなら、3つめの返り値は
   "True" になります。 "format()" メソッドの再帰呼び出しではこのディク
   ショナリのコンテナに対してさらにエントリを加えます。 3つめの引数
   *maxlevels* で再帰呼び出しのレベルを制限します。制限しない場合、
   "0" になります。この引数は再帰呼び出しでそのまま渡されます。 4つめ
   の引数 *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'}
