"pprint" --- データの整形表示
*****************************

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

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

"pprint" モジュールは、任意の Python データ構造を、インタープリタへの
入力に使える形式で「整形表示」する機能を提供します。 整形するデータ構
造に Python の基本的な型以外のオブジェクトが含まれていると、その表現を
読み込めない場合があります。 例えば、ファイル、ソケット、クラスなど、
Python のリテラルで表せないオブジェクトが含まれる場合が該当します。

整形された表現では、可能な限りオブジェクトを一行に収め、指定した幅に収
まらない場合は複数行に分割します。 幅は *width* 引数で調整でき、デフォ
ルトは 80 文字です。

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

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


関数
====

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

   *object* のフォーマットされた表現を出力して、その後に newline を続
   けます。この関数は、対話型インタプリタの中で値を調査するために
   "print()" 関数の代わりに使用されることがあります。Tips： さらに、ス
   コープ内で使用するために "print = pprint.pp" を再代入することができ
   ます)。

   パラメータ:
      * **object** -- 表示するオブジェクトです。

      * **stream** (*file-like object* | None) -- "write()" メソッドを
        呼び出して出力を書き込む、ファイルライクオブジェクトです。
        "None" (デフォルト) の場合は "sys.stdout" を使います。

      * **indent** (*int*) -- 入れ子レベルごとに追加されるインデントの
        量を指定します。

      * **width** (*int*) -- 出力の1行あたり最大文字数を指定します。構
        造が幅の制約の中で整形できない場合、最善の努力がなされます。

      * **depth** (*int** | **None*) -- 表示される入れ子レベルの数を制
        御します。表示されるデータ構造が深すぎる場合、含まれる次のレベ
        ルは "..." で置き換えられます。"None" （デフォルト）の場合、フ
        ォーマットされるオブジェクトの深さに制約はありません。

      * **compact** (*bool*) -- 長い *シーケンス* の整形方法を制御しま
        す。 "False" (デフォルト) の場合、シーケンスの各要素を別々の行
        に整形します。 そうでなければ、各出力行に *width* の範囲内でで
        きるだけ多くの要素を並べます。 *expand* とは併用できません。

      * **expand** (*bool*) -- "True" の場合、開き括弧の後に改行を入れ
        、続く内容を一段深くインデントします。 整形表示した JSON と似
        た形式になります。 *compact* とは併用できません。

      * **sort_dicts** (*bool*) -- Trueの場合、辞書は辞書のキー順にソ
        ートされて整形されます。そうでなければ挿入順に表示されます（デ
        フォルト）。

      * **underscore_numbers** (*bool*) -- Trueの場合、整数は "_" で3
        桁区切りされて表示されます。そうでなければアンダースコアは表示
        されません（デフォルト）。

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

   Added in version 3.8.

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

   バージョン 3.11 で変更: "sys.stdout" が "None" の場合、書き込みを試
   みなくなりました。

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

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

   "pp()" の別名ですが、*sort_dicts* のデフォルト値が "True" になって
   いるため、辞書のキーを自動的にソートします。 必要に応じて、この値が
   デフォルトで "False" の "pp()" を使ってください。

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

   *object* を整形した表現を文字列として返します。 *indent*、*width*、
   *depth*、*compact*、*expand*、*sort_dicts*、*underscore_numbers* は
   、整形用の引数として "PrettyPrinter" コンストラクターに渡されます。
   それぞれの意味は上記の説明と同じです。

pprint.isreadable(object)

   オブジェクトの整形された表現が「読み込み可能」、つまり "eval()" で
   元の値を再構成できるかどうかを返します。 再帰的なオブジェクトに対し
   ては常に "False" を返します。

   >>> pprint.isreadable(stuff)
   False

pprint.isrecursive(object)

   *object* の表現に再帰が必要かどうかを判定します。 この関数には、下
   記の "saferepr()" と同じ制限があり、再帰的なオブジェクトを検出でき
   なかった場合は "RecursionError" を送出することがあります。

pprint.saferepr(object)

   一般的なデータ構造で再帰を防ぎながら、*object* の文字列表現を返しま
   す。 対応するのは、"dict"、"list"、"tuple" のインスタンス、または
   "__repr__" をオーバーライドしていないそれらのサブクラスのインスタン
   スです。 オブジェクトの表現に再帰的な項目が現れる場合、その参照は
   "<Recursion on typename with id=number>" と表されます。 それ以外の
   整形は行いません。

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


PrettyPrinter オブジェクト
==========================

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

   "PrettyPrinter" インスタンスを作成します。

   引数の意味は "pp()" と同じです。 ただし、順序が異なり、*sort_dicts*
   のデフォルト値は "True" です。

   >>> 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']
   >>> pp = pprint.PrettyPrinter(width=41, expand=True, indent=3)
   >>> 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', (...)))))))

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

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

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

   バージョン 3.11 で変更: "sys.stdout" が "None" の場合、書き込みを試
   みなくなりました。

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

"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)

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


使用例
======

"pp()" 関数のいくつかの用途とそのパラメータを実証するために、PyPI から
プロジェクトに関する情報を取って来ましょう:

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

その基本形式では、 "pp()" はオブジェクト全体を表示します:

   >>> pprint.pp(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.pp(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.pp(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'}

最後に、*expand* 引数を使うと、整形表示した JSON のような形式にできま
す。 *indent* を大きめの値にすると、より見やすくなります。

   >>> pprint.pp(project_info, indent=4, expand=True)
   {
      '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},
      'dynamic': None,
      'home_page': 'https://github.com/pypa/sampleproject',
      'keywords': 'sample setuptools development',
      'license': 'MIT',
      'license_expression': None,
      'license_files': None,
      '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',
      },
      'provides_extra': None,
      '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',
      'yanked': False,
      'yanked_reason': None,
   }
