如何在 Python 中使用 Pretty Print 美化数据结构

2025 年 1 月 11 日 | 阅读 25 分钟

Python 中的 pprint (Pretty Print) 模块旨在提高字典和列表等复杂数据结构的易读性。当处理嵌套或大型数据集时,如果输出显示在一行或格式不佳,则难以解释。pprint 模块通过适当的缩进和换行符整齐地组织数据,使开发人员更容易阅读和理解。

这在调试或需要打印数据进行审查时特别有用。它通过将长或嵌套结构分解为更小、更易于管理的片段来处理它们。该模块提供了自定义输出的灵活性,例如调整每行的宽度或限制嵌套结构的显示深度。此外,它可以将数据格式化为字符串而不是直接打印,从而允许进一步操作。

在开始探索 pprint 的可能性之前,我们需要使用 urllib 发送查询以获取一些信息。第一步是创建 HTTP 请求。它将向 JSON Placeholder 发出请求,以获取一些关于用户的虚假详细信息。请求,然后将结果放入字典中。

示例

在这里,我们将使用 GET 请求创建一个初始请求,然后使用 json.loads() 将结果转换为字典。现在字典是一个数组。下一步是使用 print() 打印内容。

代码

输出

如果我们的控制台设置已配置,它可能会显示为一行。此外,我们的控制台输出可能已激活自动换行设置,这是最常见的情况。不幸的是,这并没有使我们的输出友好!

如果我们查看第一个和最后一个字符,我们会发现它似乎是一个清单。可以开始编写一个无限循环来打印项目。

代码

输出

一个 for 循环 在单独的行上打印每个对象。但是,即使每个对象也会占用比一行更多的空间。以这种方式打印可能有助于提高效率;但是,这不是最佳解决方案。这个示例是一个非常基本的数据结构,但是如果是一个大 100 倍的深度嵌套字典会怎样呢?

当然,我们可以使用递归技术编写一个程序来找出打印所有内容的方法。我们最终可能会编写一整套函数来理解数据的性质!但是,我们可能会遇到一些不允许我们使用这种方法的情况。

如何使用 pprint 模块

pprint 是一个 Python 模块,可以令人愉悦地打印数据结构。它作为 Python 标准库的一部分已经存在很长时间了;因此,无需将其作为单独的程序安装。我们所要做的就是安装它的函数 pprint() 函数。

在 Python 中使用 pprint 模块

  1. 导入: 首先,您需要导入 pprint 模块才能使用其功能。
  2. 美观打印数据: pprint 模块的主要功能是整齐地显示复杂的 数据结构,例如字典或列表。它使用适当的换行符和缩进组织数据,使其更易于阅读,尤其是在处理嵌套数据时。
  3. 存储格式化数据: 如果您需要将数据的整齐格式化版本存储为字符串以备将来使用,可以使用将数据格式化而不是直接打印的函数来实现。

简而言之,pprint 有助于以更易于阅读的格式显示和管理复杂数据。

代码

我们不是像上面那样使用标准的 print(users) 方法,而是可以调用我们最喜欢的新函数来生成美观的输出。

代码

此函数会生成其用户——但以现代化且吸引人的方式。

输出

[{'address': {'city': 'Gwenborough',
              'geo': {'lat': '-37.3159', 'lng': '81.1496'},
              'street': 'Kulas Light',
              'suite': 'Apt. 556',
              'zipcode': '92998-3874'},
  'company': {'bs': 'harness real-time e-markets',
              'catchPhrase': 'Multi-layered client-server neural-net',
              'name': 'Romaguera-Crona'},
  'email': 'Sincere@april.biz',
  'id': 1,
  'name': 'Leanne Graham',
  'phone': '1-770-736-8031 x56442',
  'username': 'Bret',
  'website': 'hildegard.org'},
 {'address': {'city': 'Wisokyburgh',
              'geo': {'lat': '-43.9509', 'lng': '-34.4618'},
              'street': 'Victor Plains',
              'suite': 'Suite 879',
              'zipcode': '90566-7771'},
  'company': {'bs': 'synergize scalable supply-chains',
              'catchPhrase': 'Proactive didactic contingency',
              'name': 'Deckow-Crist'},
  'email': 'Shanna@melissa.tv',
  'id': 2,
  'name': 'Ervin Howell',
  'phone': '010-692-6593 x09125',
  'username': 'Antonette',
  'website': 'anastasia.net'},
 {'address': {'city': 'McKenziehaven',
              'geo': {'lat': '-68.6102', 'lng': '-47.0653'},
              'street': 'Douglas Extension',
              'suite': 'Suite 847',
              'zipcode': '59590-4157'},
  'company': {'bs': 'e-enable strategic applications',
              'catchPhrase': 'Face to face bifurcated interface',
              'name': 'Romaguera-Jacobson'},
  'email': 'Nathan@yesenia.net',
  'id': 3,
  'name': 'Clementine Bauch',
  'phone': '1-463-123-4447',
  'username': 'Samantha',
  'website': 'ramiro.info'},
 {'address': {'city': 'South Elvis',
              'geo': {'lat': '29.4572', 'lng': '-164.2990'},
              'street': 'Hoeger Mall',
              'suite': 'Apt. 692',
              'zipcode': '53919-4257'},
  'company': {'bs': 'transition cutting-edge web services',
              'catchPhrase': 'Multi-tiered zero tolerance productivity',
              'name': 'Robel-Corkery'},
  'email': 'Julianne.OConner@kory.org',
  'id': 4,
  'name': 'Patricia Lebsack',
  'phone': '493-170-9623 x156',
  'username': 'Karianne',
  'website': 'kale.biz'},
 {'address': {'city': 'Roscoeview',
              'geo': {'lat': '-31.8129', 'lng': '62.5342'},
              'street': 'Skiles Walks',
              'suite': 'Suite 351',
              'zipcode': '33263'},
  'company': {'bs': 'revolutionize end-to-end systems',
              'catchPhrase': 'User-centric fault-tolerant solution',
              'name': 'Keebler LLC'},
  'email': 'Lucio_Hettinger@annie.ca',
  'id': 5,
  'name': 'Chelsey Dietrich',
  'phone': '(254)954-1289',
  'username': 'Kamren',
  'website': 'demarco.info'},
 {'address': {'city': 'South Christy',
              'geo': {'lat': '-71.4197', 'lng': '71.7478'},
              'street': 'Norberto Crossing',
              'suite': 'Apt. 950',
              'zipcode': '23505-1337'},
  'company': {'bs': 'e-enable innovative applications',
              'catchPhrase': 'Synchronised bottom-line interface',
              'name': 'Considine-Lockman'},
  'email': 'Karley_Dach@jasper.info',
  'id': 6,
  'name': 'Mrs. Dennis Schulist',
  'phone': '1-477-935-8478 x6430',
  'username': 'Leopoldo_Corkery',
  'website': 'ola.org'},
 {'address': {'city': 'Howemouth',
              'geo': {'lat': '24.8918', 'lng': '21.8984'},
              'street': 'Rex Trail',
              'suite': 'Suite 280',
              'zipcode': '58804-1099'},
  'company': {'bs': 'generate enterprise e-tailers',
              'catchPhrase': 'Configurable multimedia task-force',
              'name': 'Johns Group'},
  'email': 'Telly.Hoeger@billy.biz',
  'id': 7,
  'name': 'Kurtis Weissnat',
  'phone': '210.067.6132',
  'username': 'Elwyn.Skiles',
  'website': 'elvis.io'},
 {'address': {'city': 'Aliyaview',
              'geo': {'lat': '-14.3990', 'lng': '-120.7677'},
              'street': 'Ellsworth Summit',
              'suite': 'Suite 729',
              'zipcode': '45169'},
  'company': {'bs': 'e-enable extensible e-tailers',
              'catchPhrase': 'Implemented secondary concept',
              'name': 'Abernathy Group'},
  'email': 'Sherwood@rosamond.me',
  'id': 8,
  'name': 'Nicholas Runolfsdottir V',
  'phone': '586.493.6943 x140',
  'username': 'Maxime_Nienow',
  'website': 'jacynthe.com'},
 {'address': {'city': 'Bartholomebury',
              'geo': {'lat': '24.6463', 'lng': '-168.8889'},
              'street': 'Dayna Park',
              'suite': 'Suite 449',
              'zipcode': '76495-3109'},
  'company': {'bs': 'aggregate real-time technologies',
              'catchPhrase': 'Switchable contextually-based project',
              'name': 'Yost and Sons'},
  'email': 'Chaim_McDermott@dana.io',
  'id': 9,
  'name': 'Glenna Reichert',
  'phone': '(775)976-6794 x41206',
  'username': 'Delphine',
  'website': 'conrad.com'},
 {'address': {'city': 'Lebsackbury',
              'geo': {'lat': '-38.2386', 'lng': '57.2232'},
              'street': 'Kattie Turnpike',
              'suite': 'Suite 198',
              'zipcode': '31428-2261'},
  'company': {'bs': 'target end-to-end models',
              'catchPhrase': 'Centralized empowering task-force',
              'name': 'Hoeger LLC'},
  'email': 'Rey.Padberg@karina.biz',
  'id': 10,
  'name': 'Clementina DuBuque',
  'phone': '024-648-3804',
  'username': 'Moriah.Stanton',
  'website': 'ambrose.net'}]

字典提供了视觉缩进的键。这使得扫描数据结构和视觉分析它们变得更加容易。

如果用户喜欢尽可能少地输入,他们会喜欢 pprint() 的别名 pp()

代码

输出

{'id': 1,
 'name': 'Leanne Graham',
 'username': 'Bret',
 'email': 'Sincere@april.biz',
 'address': {'street': 'Kulas Light',
             'suite': 'Apt. 556',
             'city': 'Gwenborough',
             'zipcode': '92998-3874',
             'geo': {'lat': '-37.3159', 'lng': '81.1496'}},
 'phone': '1-770-736-8031 x56442',
 'website': 'hildegard.org',
 'company': {'name': 'Romaguera-Crona',
             'catchPhrase': 'Multi-layered client-server neural-net',
             'bs': 'harness real-time e-markets'}}
{'id': 2,
 'name': 'Ervin Howell',
 'username': 'Antonette',
 'email': 'Shanna@melissa.tv',
 'address': {'street': 'Victor Plains',
             'suite': 'Suite 879',
             'city': 'Wisokyburgh',
             'zipcode': '90566-7771',
             'geo': {'lat': '-43.9509', 'lng': '-34.4618'}},
 'phone': '010-692-6593 x09125',
 'website': 'anastasia.net',
 'company': {'name': 'Deckow-Crist',
             'catchPhrase': 'Proactive didactic contingency',
             'bs': 'synergize scalable supply-chains'}}
{'id': 3,
 'name': 'Clementine Bauch',
 'username': 'Samantha',
 'email': 'Nathan@yesenia.net',
 'address': {'street': 'Douglas Extension',
             'suite': 'Suite 847',
             'city': 'McKenziehaven',
             'zipcode': '59590-4157',
             'geo': {'lat': '-68.6102', 'lng': '-47.0653'}},
 'phone': '1-463-123-4447',
 'website': 'ramiro.info',
 'company': {'name': 'Romaguera-Jacobson',
             'catchPhrase': 'Face to face bifurcated interface',
             'bs': 'e-enable strategic applications'}}
{'id': 4,
 'name': 'Patricia Lebsack',
 'username': 'Karianne',
 'email': 'Julianne.OConner@kory.org',
 'address': {'street': 'Hoeger Mall',
             'suite': 'Apt. 692',
             'city': 'South Elvis',
             'zipcode': '53919-4257',
             'geo': {'lat': '29.4572', 'lng': '-164.2990'}},
 'phone': '493-170-9623 x156',
 'website': 'kale.biz',
 'company': {'name': 'Robel-Corkery',
             'catchPhrase': 'Multi-tiered zero tolerance productivity',
             'bs': 'transition cutting-edge web services'}}
{'id': 5,
 'name': 'Chelsey Dietrich',
 'username': 'Kamren',
 'email': 'Lucio_Hettinger@annie.ca',
 'address': {'street': 'Skiles Walks',
             'suite': 'Suite 351',
             'city': 'Roscoeview',
             'zipcode': '33263',
             'geo': {'lat': '-31.8129', 'lng': '62.5342'}},
 'phone': '(254)954-1289',
 'website': 'demarco.info',
 'company': {'name': 'Keebler LLC',
             'catchPhrase': 'User-centric fault-tolerant solution',
             'bs': 'revolutionize end-to-end systems'}}
{'id': 6,
 'name': 'Mrs. Dennis Schulist',
 'username': 'Leopoldo_Corkery',
 'email': 'Karley_Dach@jasper.info',
 'address': {'street': 'Norberto Crossing',
             'suite': 'Apt. 950',
             'city': 'South Christy',
             'zipcode': '23505-1337',
             'geo': {'lat': '-71.4197', 'lng': '71.7478'}},
 'phone': '1-477-935-8478 x6430',
 'website': 'ola.org',
 'company': {'name': 'Considine-Lockman',
             'catchPhrase': 'Synchronised bottom-line interface',
             'bs': 'e-enable innovative applications'}}
{'id': 7,
 'name': 'Kurtis Weissnat',
 'username': 'Elwyn.Skiles',
 'email': 'Telly.Hoeger@billy.biz',
 'address': {'street': 'Rex Trail',
             'suite': 'Suite 280',
             'city': 'Howemouth',
             'zipcode': '58804-1099',
             'geo': {'lat': '24.8918', 'lng': '21.8984'}},
 'phone': '210.067.6132',
 'website': 'elvis.io',
 'company': {'name': 'Johns Group',
             'catchPhrase': 'Configurable multimedia task-force',
             'bs': 'generate enterprise e-tailers'}}
{'id': 8,
 'name': 'Nicholas Runolfsdottir V',
 'username': 'Maxime_Nienow',
 'email': 'Sherwood@rosamond.me',
 'address': {'street': 'Ellsworth Summit',
             'suite': 'Suite 729',
             'city': 'Aliyaview',
             'zipcode': '45169',
             'geo': {'lat': '-14.3990', 'lng': '-120.7677'}},
 'phone': '586.493.6943 x140',
 'website': 'jacynthe.com',
 'company': {'name': 'Abernathy Group',
             'catchPhrase': 'Implemented secondary concept',
             'bs': 'e-enable extensible e-tailers'}}
{'id': 9,
 'name': 'Glenna Reichert',
 'username': 'Delphine',
 'email': 'Chaim_McDermott@dana.io',
 'address': {'street': 'Dayna Park',
             'suite': 'Suite 449',
             'city': 'Bartholomebury',
             'zipcode': '76495-3109',
             'geo': {'lat': '24.6463', 'lng': '-168.8889'}},
 'phone': '(775)976-6794 x41206',
 'website': 'conrad.com',
 'company': {'name': 'Yost and Sons',
             'catchPhrase': 'Switchable contextually-based project',
             'bs': 'aggregate real-time technologies'}}
{'id': 10,
 'name': 'Clementina DuBuque',
 'username': 'Moriah.Stanton',
 'email': 'Rey.Padberg@karina.biz',
 'address': {'street': 'Kattie Turnpike',
             'suite': 'Suite 198',
             'city': 'Lebsackbury',
             'zipcode': '31428-2261',
             'geo': {'lat': '-38.2386', 'lng': '57.2232'}},
 'phone': '024-648-3804',
 'website': 'ambrose.net',
 'company': {'name': 'Hoeger LLC',
             'catchPhrase': 'Centralized empowering task-force',
             'bs': 'target end-to-end models'}}

pp() 作为 pprint() 的包装器,其行为相同。

即使是默认输出也可能太大了,我们无法首先阅读。也许我们只是想确认我们正在处理一个包含普通对象的列表。我们可以调整输出以实现此目的。

pprint() 可以通过各种参数处理这些情况。这使我们甚至可以使最基本的数据结构看起来很美观。

如何探索 pprint() 的可选参数

本节将解释 pprint() 允许的所有参数。我们有七个选项可以配置我们的 Python 式美观打印机。它们不必全部使用,但有些将比其他更有用。我们将发现深度是最有用的一个。

如何总结我们的数据:深度

深度是最有用的参数之一。如果达到指定的深度,此 Python 命令将打印用户的完整内容。它还将保持美观。省略号替换更深层数据结构的内容。

代码

输出

[{...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}]

这将立即显示它确实是字典的列表。我们可以扩展深度以探索更多数据结构。这将打印用户中字典的所有顶级键。

代码

输出

[{'address': {'city': 'Gwenborough',
              'geo': {...},
              'street': 'Kulas Light',
              'suite': 'Apt. 556',
              'zipcode': '92998-3874'},
  'company': {'bs': 'harness real-time e-markets',
              'catchPhrase': 'Multi-layered client-server neural-net',
              'name': 'Romaguera-Crona'},
  'email': 'Sincere@april.biz',
  'id': 1,
  'name': 'Leanne Graham',
  'phone': '1-770-736-8031 x56442',
  'username': 'Bret',
  'website': 'hildegard.org'},
 {'address': {'city': 'Wisokyburgh',
              'geo': {...},
              'street': 'Victor Plains',
              'suite': 'Suite 879',
              'zipcode': '90566-7771'},
  'company': {'bs': 'synergize scalable supply-chains',
              'catchPhrase': 'Proactive didactic contingency',
              'name': 'Deckow-Crist'},
  'email': 'Shanna@melissa.tv',
  'id': 2,
  'name': 'Ervin Howell',
  'phone': '010-692-6593 x09125',
  'username': 'Antonette',
  'website': 'anastasia.net'},
 {'address': {'city': 'McKenziehaven',
              'geo': {...},
              'street': 'Douglas Extension',
              'suite': 'Suite 847',
              'zipcode': '59590-4157'},
  'company': {'bs': 'e-enable strategic applications',
              'catchPhrase': 'Face to face bifurcated interface',
              'name': 'Romaguera-Jacobson'},
  'email': 'Nathan@yesenia.net',
  'id': 3,
  'name': 'Clementine Bauch',
  'phone': '1-463-123-4447',
  'username': 'Samantha',
  'website': 'ramiro.info'},
 {'address': {'city': 'South Elvis',
              'geo': {...},
              'street': 'Hoeger Mall',
              'suite': 'Apt. 692',
              'zipcode': '53919-4257'},
  'company': {'bs': 'transition cutting-edge web services',
              'catchPhrase': 'Multi-tiered zero tolerance productivity',
              'name': 'Robel-Corkery'},
  'email': 'Julianne.OConner@kory.org',
  'id': 4,
  'name': 'Patricia Lebsack',
  'phone': '493-170-9623 x156',
  'username': 'Karianne',
  'website': 'kale.biz'},
 {'address': {'city': 'Roscoeview',
              'geo': {...},
              'street': 'Skiles Walks',
              'suite': 'Suite 351',
              'zipcode': '33263'},
  'company': {'bs': 'revolutionize end-to-end systems',
              'catchPhrase': 'User-centric fault-tolerant solution',
              'name': 'Keebler LLC'},
  'email': 'Lucio_Hettinger@annie.ca',
  'id': 5,
  'name': 'Chelsey Dietrich',
  'phone': '(254)954-1289',
  'username': 'Kamren',
  'website': 'demarco.info'},
 {'address': {'city': 'South Christy',
              'geo': {...},
              'street': 'Norberto Crossing',
              'suite': 'Apt. 950',
              'zipcode': '23505-1337'},
  'company': {'bs': 'e-enable innovative applications',
              'catchPhrase': 'Synchronised bottom-line interface',
              'name': 'Considine-Lockman'},
  'email': 'Karley_Dach@jasper.info',
  'id': 6,
  'name': 'Mrs. Dennis Schulist',
  'phone': '1-477-935-8478 x6430',
  'username': 'Leopoldo_Corkery',
  'website': 'ola.org'},
 {'address': {'city': 'Howemouth',
              'geo': {...},
              'street': 'Rex Trail',
              'suite': 'Suite 280',
              'zipcode': '58804-1099'},
  'company': {'bs': 'generate enterprise e-tailers',
              'catchPhrase': 'Configurable multimedia task-force',
              'name': 'Johns Group'},
  'email': 'Telly.Hoeger@billy.biz',
  'id': 7,
  'name': 'Kurtis Weissnat',
  'phone': '210.067.6132',
  'username': 'Elwyn.Skiles',
  'website': 'elvis.io'},
 {'address': {'city': 'Aliyaview',
              'geo': {...},
              'street': 'Ellsworth Summit',
              'suite': 'Suite 729',
              'zipcode': '45169'},
  'company': {'bs': 'e-enable extensible e-tailers',
              'catchPhrase': 'Implemented secondary concept',
              'name': 'Abernathy Group'},
  'email': 'Sherwood@rosamond.me',
  'id': 8,
  'name': 'Nicholas Runolfsdottir V',
  'phone': '586.493.6943 x140',
  'username': 'Maxime_Nienow',
  'website': 'jacynthe.com'},
 {'address': {'city': 'Bartholomebury',
              'geo': {...},
              'street': 'Dayna Park',
              'suite': 'Suite 449',
              'zipcode': '76495-3109'},
  'company': {'bs': 'aggregate real-time technologies',
              'catchPhrase': 'Switchable contextually-based project',
              'name': 'Yost and Sons'},
  'email': 'Chaim_McDermott@dana.io',
  'id': 9,
  'name': 'Glenna Reichert',
  'phone': '(775)976-6794 x41206',
  'username': 'Delphine',
  'website': 'conrad.com'},
 {'address': {'city': 'Lebsackbury',
              'geo': {...},
              'street': 'Kattie Turnpike',
              'suite': 'Suite 198',
              'zipcode': '31428-2261'},
  'company': {'bs': 'target end-to-end models',
              'catchPhrase': 'Centralized empowering task-force',
              'name': 'Hoeger LLC'},
  'email': 'Rey.Padberg@karina.biz',
  'id': 10,
  'name': 'Clementina DuBuque',
  'phone': '024-648-3804',
  'username': 'Moriah.Stanton',
  'website': 'ambrose.net'}]

我们现在可以快速验证所有字典是否具有相同的顶级键。这是一个重要的观察,特别是如果我们的任务是开发使用此类数据的应用程序。

如何为我们的数据留出空间:indent

indent 参数确定输出中每个级别的缩进程度。1 的默认缩进是一个空格字符。

代码

输出

{'address': {...},
 'company': {...},
 'email': 'Sincere@april.biz',
 'id': 1, 
 'name': 'Leanne Graham',
 'phone': '1-770-736-8031 x56442',
 'username': 'Bret',
 'website': 'hildegard.org'}

代码

输出

{   'address': {...},
    'company': {...},
    'email': 'Sincere@april.biz',
    'id': 1,
    'name': 'Leanne Graham',
    'phone': '1-770-736-8031 x56442',
    'username': 'Bret',
    'website': 'hildegard.org'}

pprint() 缩进行为最重要的方面是使所有键在视觉上对齐。indent 参数以及键的位置将决定应用多少缩进。

indent 参数用于确定缩进量。因此没有嵌套。在这两个示例中,我们可以注意到开花括号 ({) 如何作为第一个键的缩进单位。在第一个示例中,第一个键的单个开引号紧跟在 { 之后,没有空格,因为 indent 已设置为 1。

嵌套是指缩进应用于行中的第一个元素,然后 pprint() 将所有后续元素与第一个对齐。如果我们将用户设置为 4,则第一个元素将有四个字符的缩进,嵌套元素将有八个字符的缩进。这是因为缩进从第一个键的末尾开始。

代码

输出

{   'address': {   'city': 'Gwenborough',
                   'geo': {...},
                   'street': 'Kulas Light',
                   'suite': 'Apt. 556',
                   'zipcode': '92998-3874'},
    'company': {   'bs': 'harness real-time e-markets',
                   'catchPhrase': 'Multi-layered client-server neural-net',
                   'name': 'Romaguera-Crona'},
    'email': 'Sincere@april.biz',
    'id': 1,
    'name': 'Leanne Graham',
    'phone': '1-770-736-8031 x56442',
    'username': 'Bret',
    'website': 'hildegard.org'}

如何限制我们的行长:width

pprint() 默认每行只输出 80 个字符。可以通过传入 width 参数来自定义此值。pprint() 将尝试将内容放入一行中。如果数据结构的内容超出此限制,它将在新行上打印所有元素。

输出

{'address': {'city': 'Gwenborough',
             'geo': {'lat': '-37.3159', 'lng': '81.1496'},
             'street': 'Kulas Light',
             'suite': 'Apt. 556',
             'zipcode': '92998-3874'},
 'company': {'bs': 'harness real-time e-markets',
             'catchPhrase': 'Multi-layered client-server neural-net',
             'name': 'Romaguera-Crona'},
 'email': 'Sincere@april.biz',
 'id': 1,
 'name': 'Leanne Graham',
 'phone': '1-770-736-8031 x56442',
 'username': 'Bret',
 'website': 'hildegard.org'}

当我们将 width 保持为默认的 80 个字符时,users[0]['address']['geo'] 中的字典只包含“lat”和“lng”属性。这意味着缩进加上打印字典所需的字符数(包括其间的任何空格)的总和小于 80 个字符,因此 pprint() 将其全部放在一行上。

用户的 [0]['company'] 字典太大,因此 print() 将每个键放在单独的行上。这适用于字典、集合、元组和列表。

代码

输出

{'address': {'city': 'Gwenborough', 'geo': {'lat': '-37.3159', 'lng': '81.1496'}, 'street': 'Kulas Light', 'suite': 'Apt. 556', 'zipcode': '92998-3874'},
 'company': {'bs': 'harness real-time e-markets', 'catchPhrase': 'Multi-layered client-server neural-net', 'name': 'Romaguera-Crona'},
 'email': 'Sincere@april.biz',
 'id': 1, 
 'name': 'Leanne Graham',
 'phone': '1-770-736-8031 x56442',
 'username': 'Bret',
 'website': 'hildegard.org'}

我们可以通过将 width 值设置为 160 将所有嵌套字典条目放在一行上。我们甚至可以更进一步,将 width 设置为 500。这将在一行上打印整个字典。

代码

输出

{'address': {'city': 'Gwenborough', 'geo': {'lat': '-37.3159', 'lng': '81.1496'}, 'street': 'Kulas Light', 'suite': 'Apt. 556', 'zipcode': '92998-3874'}, 'company': {'bs': 'harness real-time e-markets', 'catchPhrase': 'Multi-layered client-server neural-net', 'name': 'Romaguera-Crona'}, 'email': 'Sincere@april.biz', 'id': 1, 'name': 'Leanne Graham', 'phone': '1-770-736-8031 x56442', 'username': 'Bret', 'website': 'hildegard.org'}

这将向我们展示将宽度设置为大值的结果。或者,我们可以将宽度设置为较低的值,例如 1。这将确保每个数据结构在单独的行上显示其组件。视觉缩进仍将用于对齐组件。

代码

输出

{'address': {'city': 'Gwenborough',
             'geo': {'lat': '-37.3159',
                     'lng': '81.1496'},
             'street': 'Kulas '
                       'Light',
             'suite': 'Apt. '
                      '556',
             'zipcode': '92998-3874'},
 'company': {'bs': 'harness '
                   'real-time '
                   'e-markets',
             'catchPhrase': 'Multi-layered '
                            'client-server '
                            'neural-net',
             'name': 'Romaguera-Crona'},
 'email': 'Sincere@april.biz',
 'id': 1,
 'name': 'Leanne '
         'Graham',
 'phone': '1-770-736-8031 '
          'x56442',
 'username': 'Bret',
 'website': 'hildegard.org'}

很难让 Python 的 pprint() 函数打印得难看。它会尽力看起来很美!

此示例向我们展示了打印机如何分解长文本行。请注意 users[0]["company"]["catchPhrase"],最初是“Multi-layered client-server neural-net”,是如何在每个空格处拆分的。因为它会很难阅读,所以打印机不会完全拆分此字符串。

如何压缩我们的长序列:compact

人们可能会认为 compact 仅指“宽度”部分中描述的行为。Compact 决定了数据结构是显示在一行还是两行上。Compact 仅在行 长于 时影响输出。

如果 compact 为 True,则输出将换行到下一行。如果数据结构大于宽度,则默认行为是每个元素出现在其行上。

代码

输出

[{...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}]

代码

输出

[{...},
 {...},
 {...},
 {...},
 {...},
 {...},
 {...},
 {...},
 {...},
 {...}]

代码

输出

[{...}, {...},
 {...}, {...},
 {...}, {...},
 {...}, {...},
 {...}, {...}]

使用默认设置美观打印此列表会将列表的缩写版本打印在一行上。通过将宽度限制为 20 个字符。这将强制 pprint() 在单独的行中输出每个列表元素。如果我们将 compact 的值选择为 true,则列表将在 20 个字符处换行,并且比通常格式化的要小得多。

对于包含短元素的长序列来说,compact 是一个很好的选择,否则这些元素将占用大量行并使输出不那么清晰。

如何引导我们的输出:stream

stream 参数指的是 pprint() 函数的输出。默认情况下,它被发送到 print() 所到的确切位置。具体来说,它是 sys.stdout,这是 Python 中的一个实际文件对象。但是,我们可以将此信息转发到任何其他文件对象,就像我们可以使用 print() 函数一样。

输出

Content of the output.txt File:
 [{'address': {'city': 'Gwenborough',
              'geo': {'lat': '-37.3159', 'lng': '81.1496'},
              'street': 'Kulas Light',
              'suite': 'Apt. 556',
              'zipcode': '92998-3874'},
  'company': {'bs': 'harness real-time e-markets',
              'catchPhrase': 'Multi-layered client-server neural-net',
              'name': 'Romaguera-Crona'},
  'email': 'Sincere@april.biz',
  'id': 1,
  'name': 'Leanne Graham',
  'phone': '1-770-736-8031 x56442',
  'username': 'Bret',
  'website': 'hildegard.org'},
 {'address': {'city': 'Wisokyburgh',
              'geo': {'lat': '-43.9509', 'lng': '-34.4618'},
              'street': 'Victor Plains',
              'suite': 'Suite 879',
              'zipcode': '90566-7771'},
  'company': {'bs': 'synergize scalable supply-chains',
              'catchPhrase': 'Proactive didactic contingency',
              'name': 'Deckow-Crist'},
  'email': 'Shanna@melissa.tv',
  'id': 2,
  'name': 'Ervin Howell',
  'phone': '010-692-6593 x09125',
  'username': 'Antonette',
  'website': 'anastasia.net'},
 {'address': {'city': 'McKenziehaven',
              'geo': {'lat': '-68.6102', 'lng': '-47.0653'},
              'street': 'Douglas Extension',
              'suite': 'Suite 847',
              'zipcode': '59590-4157'},
  'company': {'bs': 'e-enable strategic applications',
              'catchPhrase': 'Face to face bifurcated interface',
              'name': 'Romaguera-Jacobson'},
  'email': 'Nathan@yesenia.net',
  'id': 3,
  'name': 'Clementine Bauch',
  'phone': '1-463-123-4447',
  'username': 'Samantha',
  'website': 'ramiro.info'},
 {'address': {'city': 'South Elvis',
              'geo': {'lat': '29.4572', 'lng': '-164.2990'},
              'street': 'Hoeger Mall',
              'suite': 'Apt. 692',
              'zipcode': '53919-4257'},
  'company': {'bs': 'transition cutting-edge web services',
              'catchPhrase': 'Multi-tiered zero tolerance productivity',
              'name': 'Robel-Corkery'},
  'email': 'Julianne.OConner@kory.org',
  'id': 4,
  'name': 'Patricia Lebsack',
  'phone': '493-170-9623 x156',
  'username': 'Karianne',
  'website': 'kale.biz'},
 {'address': {'city': 'Roscoeview',
              'geo': {'lat': '-31.8129', 'lng': '62.5342'},
              'street': 'Skiles Walks',
              'suite': 'Suite 351',
              'zipcode': '33263'},
  'company': {'bs': 'revolutionize end-to-end systems',
              'catchPhrase': 'User-centric fault-tolerant solution',
              'name': 'Keebler LLC'},
  'email': 'Lucio_Hettinger@annie.ca',
  'id': 5,
  'name': 'Chelsey Dietrich',
  'phone': '(254)954-1289',
  'username': 'Kamren',
  'website': 'demarco.info'},
 {'address': {'city': 'South Christy',
              'geo': {'lat': '-71.4197', 'lng': '71.7478'},
              'street': 'Norberto Crossing',
              'suite': 'Apt. 950',
              'zipcode': '23505-1337'},
  'company': {'bs': 'e-enable innovative applications',
              'catchPhrase': 'Synchronised bottom-line interface',
              'name': 'Considine-Lockman'},
  'email': 'Karley_Dach@jasper.info',
  'id': 6,
  'name': 'Mrs. Dennis Schulist',
  'phone': '1-477-935-8478 x6430',
  'username': 'Leopoldo_Corkery',
  'website': 'ola.org'},
 {'address': {'city': 'Howemouth',
              'geo': {'lat': '24.8918', 'lng': '21.8984'},
              'street': 'Rex Trail',
              'suite': 'Suite 280',
              'zipcode': '58804-1099'},
  'company': {'bs': 'generate enterprise e-tailers',
              'catchPhrase': 'Configurable multimedia task-force',
              'name': 'Johns Group'},
  'email': 'Telly.Hoeger@billy.biz',
  'id': 7,
  'name': 'Kurtis Weissnat',
  'phone': '210.067.6132',
  'username': 'Elwyn.Skiles',
  'website': 'elvis.io'},
 {'address': {'city': 'Aliyaview',
              'geo': {'lat': '-14.3990', 'lng': '-120.7677'},
              'street': 'Ellsworth Summit',
              'suite': 'Suite 729',
              'zipcode': '45169'},
  'company': {'bs': 'e-enable extensible e-tailers',
              'catchPhrase': 'Implemented secondary concept',
              'name': 'Abernathy Group'},
  'email': 'Sherwood@rosamond.me',
  'id': 8,
  'name': 'Nicholas Runolfsdottir V',
  'phone': '586.493.6943 x140',
  'username': 'Maxime_Nienow',
  'website': 'jacynthe.com'},
 {'address': {'city': 'Bartholomebury',
              'geo': {'lat': '24.6463', 'lng': '-168.8889'},
              'street': 'Dayna Park',
              'suite': 'Suite 449',
              'zipcode': '76495-3109'},
  'company': {'bs': 'aggregate real-time technologies',
              'catchPhrase': 'Switchable contextually-based project',
              'name': 'Yost and Sons'},
  'email': 'Chaim_McDermott@dana.io',
  'id': 9,
  'name': 'Glenna Reichert',
  'phone': '(775)976-6794 x41206',
  'username': 'Delphine',
  'website': 'conrad.com'},
 {'address': {'city': 'Lebsackbury',
              'geo': {'lat': '-38.2386', 'lng': '57.2232'},
              'street': 'Kattie Turnpike',
              'suite': 'Suite 198',
              'zipcode': '31428-2261'},
  'company': {'bs': 'target end-to-end models',
              'catchPhrase': 'Centralized empowering task-force',
              'name': 'Hoeger LLC'},
  'email': 'Rey.Padberg@karina.biz',
  'id': 10,
  'name': 'Clementina DuBuque',
  'phone': '024-648-3804',
  'username': 'Moriah.Stanton',
  'website': 'ambrose.net'}]

在这种情况下,我们通过调用 open() 创建一个文件对象,然后我们将 pprint() 的 stream 参数分配给该文件中的对象。当我们浏览 output.txt 时,我们会看到它已经打印出来。

Python 确实带有自己的日志记录模块。但是,如果我们愿意,我们可以利用 pprint() 将精美的输出发送到文件,然后将它们用作日志。

如何防止字典排序:sort_dicts

虽然字典通常被归类为通常无序的数据结构,但自 Python 3.6 起,字典使用插入进行排序。

pprint() 按字母顺序对键进行排序以进行打印。

代码

输出

{'address': {...},
 'company': {...},
 'email': 'Sincere@april.biz',
 'id': 1,
 'name': 'Leanne Graham',
 'phone': '1-770-736-8031 x56442',
 'username': 'Bret',
 'website': 'hildegard.org'}

代码

输出

{'id': 1,
 'name': 'Leanne Graham',
 'username': 'Bret',
 'email': 'Sincere@april.biz',
 'address': {...},
 'phone': '1-770-736-8031 x56442',
 'website': 'hildegard.org',
 'company': {...}}

如果我们没有将 sort_dicts 选项设置为 False,则 Python 的 pprint() 会按字母顺序对键进行排序。它使字典的输出保持一致且可读,并且美观!

当 pprint() 首次引入时,字典是无序的。如果没有键的字母顺序排序,字典中的键可能每次打印都不同。

如何使我们的数字更易辨认:underscore_numbers

其 underscore_numbers 参数是 Python 3.10 实现的一项新功能,有助于使长数字更易于理解。如果到目前为止我们使用的示例不包含长数字,那么我们将需要一个全新的场景来测试此功能。

示例

输出

[12_345_678_321, 10_000_011_000_000]

如果当用户直接使用 pprint() 并且他们正在寻找美观的数字时 underscore_numbers 不起作用,这里有一个替代方案:如果他们创建 PrettyPrinter 对象,则该参数将像上面示例中那样工作。

如何创建自定义 PrettyPrinter 对象

可以创建一个具有我们设置的默认值的新 PrettyPrinter 实例。一旦我们获得了自定义 PrettyPrinter 对象的此实例,我们就可以通过在 PrettyPrinter 实例上使用 .pprint() 方法来使用它。

代码

输出

{   'id': 4,
    'name': 'Patricia Lebsack',
    'username': 'Karianne',
    'email': 'Julianne.OConner@kory.org',
    'address': {   'street': 'Hoeger Mall',
                   'suite': 'Apt. 692',
                   'city': 'South Elvis',
                   'zipcode': '53919-4257',
                   'geo': {...}},
    'phone': '493-170-9623 x156',
    'website': 'kale.biz',
    'company': {   'name': 'Robel-Corkery',
                   'catchPhrase': 'Multi-tiered zero tolerance productivity',
                   'bs': 'transition cutting-edge web services'}}

代码

输出

[12_345_678_321, 10_000_011_000_000]

通过遵循这些说明,我们可以

  • 导入 PrettyPrinter,这是一个类定义的示例
  • 使用某些参数创建一个新的类实例
  • 打印为初始用户用户
  • 定义为两个长数字的集合
  • 打印 number_list,这也演示了 underscore_numbers 的作用

用户必须注意,给 PrettyPrinter 的参数与标准 print() 参数中使用的参数相同,只是它们没有传递一个参数。在 pprint() 中,这是他们希望打印的对象。

这样,我们将能够拥有各种打印机预设,也许有一个会流向不同的流,并在我们需要时使用它们。

如何使用 pformat() 获取美观字符串

如果我们不想将 pprint() 的精美输出传输到流中怎么办?也许我们想做一些正则表达式匹配,然后替换特定的键。对于简单的字典,可能需要摆脱那些括号或引号,以使其看起来更人性化。

无论我们想对字符串的输出做什么,我们都可以使用格式 pformat() 访问所需的字符串。

示例

输出

city: South Elvis,
 geo: lat: 29.4572, lng: -164.2990,
 street: Hoeger Mall,
 suite: Apt. 692,
 zipcode: 53919-4257

pformat() 是我们可以用来连接有吸引力的打印机和输出流的工具。

另一个可能的用途是,如果我们正在开发一个 API,并且我们想为 JSON 提供一个漂亮的文本表示。JSON 字符串。我们的用户可能会很高兴!

如何处理递归数据结构

Python 函数 pprint() 是递归的,这意味着它将打印字典的所有详细信息,包括子字典的内容,依此类推。

考虑当递归程序遇到递归信息结构时它是如何工作的。假设我们有一个字典 A 和字典 B

  • A 包含一个特征 .link,它标识 B。
  • B 包含一个属性 .link,它指向 A。

如果我们的递归代码无法处理这种循环引用,它就永远不会完成打印!它将创建字母 A,然后是其子 B。但是,B 也是作为子代的 A,因此它将继续无限循环。

幸运的是,普通的 print() 函数和 pprint() 函数都可以轻松处理此问题。

示例

输出

{'link': {'link': {...}}}

示例

输出

{'link': {'link': <Recursion on dict with id=2888669445184>}}

虽然 Python 的标准 print() 缩写了输出,但 pprint() 明确提醒我们重复并添加到字典的 ID。

结论

我们已经了解了 Python 中 pprint 模块的主要用途以及使用 pprint() 模块和 PrettyPrinter 的几种方法。我们将发现 pprint() 在创建需要复杂数据结构的事物时特别有用。也许我们正在创建使用不成熟 API 的应用程序。也许我们有一个包含深度嵌套 JSON 文件的大型数据仓库。所有这些都是 pprint 成为绝佳工具的情况。

通过本课程,我们学会了

  • 导入 pprint 以在我们的应用程序中使用。
  • 使用 print 函数 pprint() 代替 print()。
  • 了解我们需要定制打印输出的所有选项。
  • 确保我们将格式化的输出保存为文本字符串,然后再打印它。
  • 创建 PrettyPrinter 的自定义实例。
  • 识别数据的递归结构并了解 Pprint() 如何处理它们。