pprint — Impresión bonita de datos

Código fuente: Lib/pprint.py


El módulo pprint proporciona la capacidad de «imprimir de forma bonita» estructuras de datos arbitrarias de Python de manera que se puede utilizar como entrada para el intérprete. Si las estructuras formateadas incluyen objetos que no son tipos fundamentales de Python, es posible que la representación no sea válida como tal para el intérprete. Esto puede darse si se incluyen objetos como archivos, sockets o clases, así como muchos otros objetos que no se pueden representar como literales de Python.

La representación formateada mantiene los objetos en una sola línea siempre que sea posible y los divide en varias líneas si no encajan dentro del ancho permitido. Se deben crear objetos PrettyPrinter de forma explícita si se necesita ajustar la restricción de ancho.

Los diccionarios se ordenan por clave antes de que se calcule la representación en pantalla.

Distinto en la versión 3.9: Soporte añadido para imprimir de forma bonita types.SimpleNamespace.

Distinto en la versión 3.10: Soporte añadido para imprimir de forma bonita dataclasses.dataclass.

El módulo pprint solo define una clase:

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

Constructor de la instancia PrettyPrinter. Este constructor interpreta varios parámetros.

stream (default sys.stdout) is a file-like object to which the output will be written by calling its write() method. If both stream and sys.stdout are None, then pprint() silently returns.

Otros valores configuran la manera en que el anidamiento de estructuras datos complejos son visualizados.

indent (por defecto 1) especifica la cantidad de sangría agregada para cada nivel de anidamiento.

depth controla el número de niveles de anidamientos que podría ser impreso; si la estructura de datos a imprimir es muy profunda, el siguiente nivel es reemplazado por .... Por defecto, no hay ninguna restricción en la profundidad de los objetos que se formatean.

width (por defecto 80) especifica el número máximo deseado de caracteres por línea en la salida. Si no se puede formatear una estructura dentro de la restricción de ancho, se hará el mejor esfuerzo.

compact impacta la forma en que secuencias largas (listas, tuplas, conjuntos, etc) son formateadas. Si compact es falso (el valor predeterminado) entonces cada elemento de una secuencia será formateada en una línea separada. Si compact es verdadero, todos los elementos que encajen en el width de cada línea de salida, lo harán.

Si sort_dicts es verdadero (el valor predeterminado), los diccionarios se formatearán con sus claves ordenadas; de lo contrario, se mostrarán en orden de inserción.

Si underscore_numbers es verdadero, los enteros se formatearán con el carácter _ para un separador de miles; de lo contrario, no se mostrarán los guiones bajos (el valor predeterminado).

Distinto en la versión 3.4: Añadido el argumento compact.

Distinto en la versión 3.8: Añadido el argumento sort_dicts.

Distinto en la versión 3.10: Se agregó el parámetro underscore_numbers.

Distinto en la versión 3.11: No longer attempts to write to sys.stdout if it is None.

>>> 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.pformat(object, indent=1, width=80, depth=None, *, compact=False, sort_dicts=True, underscore_numbers=False)

Return the formatted representation of object as a string. indent, width, depth, compact, sort_dicts and underscore_numbers are passed to the PrettyPrinter constructor as formatting parameters and their meanings are as described in its documentation above.

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

Imprime la representación formateada de object seguida de una nueva línea. Si sort_dicts es False (el valor por defecto), los diccionarios se mostrarán con sus claves según orden de inserción, de lo contrario, las claves del diccionario serán ordenadas. args y kwargs se pasarán a pprint() como parámetros de formato.

Nuevo en la versión 3.8.

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

Prints the formatted representation of object on stream, followed by a newline. If stream is None, sys.stdout is used. This may be used in the interactive interpreter instead of the print() function for inspecting values (you can even reassign print = pprint.pprint for use within a scope).

The configuration parameters stream, indent, width, depth, compact, sort_dicts and underscore_numbers are passed to the PrettyPrinter constructor and their meanings are as described in its documentation above.

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

Determina si la representación formateada de object es «legible» o si puede usarse para reconstruir el objeto usando eval(). Siempre retorna False para objetos recursivos.

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

Determine if object requires a recursive representation. This function is subject to the same limitations as noted in saferepr() below and may raise an RecursionError if it fails to detect a recursive object.

Una función extra de soporte es también definida:

pprint.saferepr(object)

Return a string representation of object, protected against recursion in some common data structures, namely instances of dict, list and tuple or subclasses whose __repr__ has not been overridden. If the representation of object exposes a recursive entry, the recursive reference will be represented as <Recursion on typename with id=number>. The representation is not otherwise formatted.

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

Objetos PrettyPrinter

Las instancias de PrettyPrinter tienen los siguientes métodos:

PrettyPrinter.pformat(object)

Retorna la representación formateada de object. Tiene en cuenta las opciones pasadas al constructor de la clase PrettyPrinter.

PrettyPrinter.pprint(object)

Imprime la representación formateada de object en la secuencia configurada, seguida de una nueva línea.

Los siguientes métodos proporcionan las implementaciones para las funciones correspondientes con los mismos nombres. Usar estos métodos en una instancia es algo más eficiente, ya que no es necesario crear nuevos objetos PrettyPrinter.

PrettyPrinter.isreadable(object)

Determina si la representación formateada de object es «legible» o si se puede usar para reconstruir su valor usando eval(). Se debe tener en cuenta que se retorna False para objetos recursivos. Si el parámetro depth de PrettyPrinter es proporcionado y el objeto es más profundo de lo permitido, también se retorna False.

PrettyPrinter.isrecursive(object)

Determina si object requiere una representación recursiva.

Este método se proporciona como un punto de entrada o método de enlace automático (hook en inglés) para permitir que las subclases modifiquen la forma en que los objetos se convierten en cadenas de caracteres. La implementación por defecto utiliza la implementación interna de saferepr().

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

Retorna tres valores: la versión formateada de object como una cadena de caracteres, una bandera que indica si el resultado es legible y una bandera que indica si se detectó recursividad. El primer argumento es el objeto a representar. El segundo es un diccionario que contiene la id() de los objetos que son parte del contexto de representación actual (contenedores directos e indirectos para object que están afectando a la representación), como las claves; si es necesario representar un objeto que ya está representado en context, el tercer valor de retorno será True. Las llamadas recursivas al método format() deben agregar entradas adicionales a los contenedores de este diccionario. El tercer argumento, maxlevels, proporciona el límite máximo de recursividad; su valor por defecto es 0. Este argumento debe pasarse sin modificaciones a las llamadas recursivas. El cuarto argumento, level, da el nivel actual; las llamadas recursivas sucesivas deben pasar un valor menor que el de la llamada actual.

Ejemplo

Para demostrar varios usos de la función pprint() y sus parámetros, busquemos información sobre un proyecto en 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']

En su forma básica, la función pprint() muestra el objeto completo:

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

El resultado puede limitarse a una cierta profundidad asignando un valor al argumento depth (... se utiliza para contenidos más «profundos»):

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

Además, se puede establecer un valor máximo de caracteres por línea asignando un valor al parámetro width. Si un objeto largo no se puede dividir, el valor dado al ancho se anulará y será excedido:

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