pprint — Datenstrukturen ansprechend ausgeben

Quellcode: Lib/pprint.py


Das Modul pprint bietet die Möglichkeit, beliebige Python-Datenstrukturen ansprechend ausgegeben zu lassen, und zwar in einer Form, die sich wieder als Eingabe für den Interpreter verwenden lässt. Enthalten die formatierten Strukturen Objekte, die keine grundlegenden Python-Typen sind, lässt sich die Darstellung unter Umständen nicht mehr laden. Das kann bei Dateien, Sockets oder Klassen der Fall sein, ebenso bei vielen anderen Objekten, die sich nicht als Python-Literale darstellen lassen.

Die formatierte Darstellung hält Objekte auf einer einzigen Zeile, sofern das möglich ist, und bricht sie auf mehrere Zeilen um, wenn sie nicht in die erlaubte Breite passen. Diese lässt sich über den Parameter width einstellen und beträgt voreingestellt 80 Zeichen.

Geändert in Version 3.9: Unterstützung für die ansprechende Ausgabe von types.SimpleNamespace hinzugefügt.

Geändert in Version 3.10: Unterstützung für die ansprechende Ausgabe von dataclasses.dataclass hinzugefügt.

Funktionen

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

Gibt die formatierte Darstellung von object aus, gefolgt von einem Zeilenumbruch. Diese Funktion lässt sich im interaktiven Interpreter anstelle der Funktion print() verwenden, um Werte anzusehen. Tipp: Innerhalb eines Geltungsbereichs kannst du print = pprint.pp zuweisen.

Parameter:
  • object – Das auszugebende Objekt.

  • stream (file-like object | None) – Ein dateiähnliches Objekt, in das die Ausgabe durch Aufruf seiner Methode write() geschrieben wird. Bei None (der Voreinstellung) wird sys.stdout verwendet.

  • indent (int) – Der Einzug, der je Verschachtelungsebene hinzukommt.

  • width (int) – Die gewünschte Höchstzahl an Zeichen je Ausgabezeile. Lässt sich eine Struktur nicht innerhalb dieser Breite formatieren, wird das bestmögliche Ergebnis angestrebt.

  • depth (int | None) – Die Anzahl der Verschachtelungsebenen, die ausgegeben werden dürfen. Ist die auszugebende Datenstruktur zu tief, wird die nächste enthaltene Ebene durch ... ersetzt. Bei None (der Voreinstellung) gibt es keine Beschränkung der Tiefe der formatierten Objekte.

  • compact (bool) – Steuert, wie lange Sequenzen formatiert werden. Bei False (der Voreinstellung) wird jedes Element einer Sequenz in eine eigene Zeile formatiert, andernfalls so viele Elemente je Ausgabezeile, wie in die width passen. Nicht mit expand vereinbar.

  • expand (bool) – Bei True folgt auf öffnende runde und eckige Klammern ein Zeilenumbruch und der nachfolgende Inhalt wird um eine Ebene eingerückt, ähnlich wie bei ansprechend ausgegebenem JSON. Nicht mit compact vereinbar.

  • sort_dicts (bool) – Bei True werden Dictionarys mit sortierten Schlüsseln formatiert, andernfalls in der Reihenfolge des Einfügens (die Voreinstellung).

  • underscore_numbers (bool) – Bei True werden ganze Zahlen mit dem Zeichen _ als Tausendertrennzeichen formatiert, andernfalls werden keine Unterstriche angezeigt (die Voreinstellung).

>>> 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.

Geändert in Version 3.10: Der Parameter underscore_numbers kam hinzu.

Geändert in Version 3.11: Es wird nicht mehr versucht, nach sys.stdout zu schreiben, wenn dieses None ist.

Geändert in Version 3.15: Der Parameter expand kam hinzu.

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

Alias für pp(), bei dem sort_dicts voreingestellt auf True steht und die Schlüssel der Dictionarys damit selbsttätig sortiert werden. Meist ist stattdessen pp() die bessere Wahl, dort steht der Wert voreingestellt auf False.

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

Gibt die formatierte Darstellung von object als Zeichenkette zurück. indent, width, depth, compact, expand, sort_dicts und underscore_numbers werden als Formatierungsparameter an den Konstruktor von PrettyPrinter übergeben. Ihre Bedeutung ist oben beschrieben.

pprint.isreadable(object)

Ermittelt, ob die formatierte Darstellung von object „lesbar“ ist, sich also mit eval() wieder in den Wert zurückverwandeln lässt. Für rekursive Objekte wird stets False zurückgegeben.

>>> pprint.isreadable(stuff)
False
pprint.isrecursive(object)

Ermittelt, ob object eine rekursive Darstellung erfordert. Für diese Funktion gelten dieselben Einschränkungen wie unten bei saferepr() beschrieben. Sie kann RecursionError auslösen, wenn sie ein rekursives Objekt nicht erkennt.

pprint.saferepr(object)

Gibt eine Zeichenkettendarstellung von object zurück, geschützt gegen Rekursion in einigen verbreiteten Datenstrukturen, nämlich Instanzen von dict, list und tuple sowie Unterklassen, deren __repr__ nicht überschrieben wurde. Legt die Darstellung des Objekts einen rekursiven Eintrag offen, wird der rekursive Verweis als <Recursion on typename with id=number> dargestellt. Darüber hinaus wird die Darstellung nicht formatiert.

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

PrettyPrinter-Objekte

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

Erzeugt eine PrettyPrinter-Instanz.

Die Argumente haben dieselbe Bedeutung wie bei pp(). Beachte, dass sie in einer anderen Reihenfolge stehen und dass sort_dicts voreingestellt True ist.

>>> 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', (...)))))))

Geändert in Version 3.4: Der Parameter compact kam hinzu.

Geändert in Version 3.8: Der Parameter sort_dicts kam hinzu.

Geändert in Version 3.10: Der Parameter underscore_numbers kam hinzu.

Geändert in Version 3.11: Es wird nicht mehr versucht, nach sys.stdout zu schreiben, wenn dieses None ist.

Geändert in Version 3.15: Der Parameter expand kam hinzu.

PrettyPrinter-Instanzen haben die folgenden Methoden:

PrettyPrinter.pformat(object)

Gibt die formatierte Darstellung von object zurück. Dabei werden die Optionen berücksichtigt, die dem Konstruktor von PrettyPrinter übergeben wurden.

PrettyPrinter.pprint(object)

Gibt die formatierte Darstellung von object auf dem eingestellten Strom aus, gefolgt von einem Zeilenumbruch.

Die folgenden Methoden stellen die Umsetzung der entsprechenden gleichnamigen Funktionen bereit. Diese Methoden an einer Instanz zu verwenden ist etwas effizienter, da keine neuen PrettyPrinter-Objekte erzeugt werden müssen.

PrettyPrinter.isreadable(object)

Ermittelt, ob die formatierte Darstellung des Objekts „lesbar“ ist, sich also mit eval() wieder in den Wert zurückverwandeln lässt. Beachte, dass für rekursive Objekte False zurückgegeben wird. Ist der Parameter depth des PrettyPrinter gesetzt und das Objekt tiefer als erlaubt, wird ebenfalls False zurückgegeben.

PrettyPrinter.isrecursive(object)

Ermittelt, ob das Objekt eine rekursive Darstellung erfordert.

Diese Methode ist als Einhängepunkt gedacht, damit Unterklassen ändern können, wie Objekte in Zeichenketten umgewandelt werden. Die voreingestellte Umsetzung verwendet das Innenleben der Umsetzung von saferepr().

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

Gibt drei Werte zurück: die formatierte Fassung von object als Zeichenkette, ein Kennzeichen dafür, ob das Ergebnis lesbar ist, und ein Kennzeichen dafür, ob Rekursion erkannt wurde. Das erste Argument ist das darzustellende Objekt. Das zweite ist ein Dictionary, dessen Schlüssel die id() jener Objekte sind, die zum aktuellen Darstellungskontext gehören (direkte und indirekte Behälter von object, die die Darstellung beeinflussen). Muss ein Objekt dargestellt werden, das in context schon vertreten ist, sollte der dritte Rückgabewert True sein. Rekursive Aufrufe der Methode format() sollten diesem Dictionary weitere Einträge für Behälter hinzufügen. Das dritte Argument, maxlevels, gibt die gewünschte Grenze für die Rekursion an. Es ist 0, wenn keine Grenze gewünscht ist. Dieses Argument sollte unverändert an rekursive Aufrufe weitergegeben werden. Das vierte Argument, level, gibt die aktuelle Ebene an. Rekursiven Aufrufen sollte ein Wert übergeben werden, der kleiner als der des aktuellen Aufrufs ist.

Beispiel

Um mehrere Verwendungen der Funktion pp() und ihrer Parameter zu zeigen, holen wir Informationen über ein Projekt von PyPI ab:

>>> 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']

In seiner Grundform zeigt pp() das gesamte Objekt:

>>> 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'}

Das Ergebnis lässt sich auf eine bestimmte depth begrenzen. Für tiefere Inhalte stehen dann Auslassungspunkte:

>>> 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'}

Außerdem lässt sich eine größte Zeichenbreite width vorschlagen. Kann ein langes Objekt nicht umgebrochen werden, wird die angegebene Breite überschritten:

>>> 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'}

Zuletzt lässt sich mit dem Parameter expand wie bei ansprechend ausgegebenem JSON formatieren. Die besten Ergebnisse erzielt ein höherer Wert für 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,
}