Title: Modern defaults for `pprint` · Issue #149189 · python/cpython · GitHub
Open Graph Title: Modern defaults for `pprint` · Issue #149189 · python/cpython
X Title: Modern defaults for `pprint` · Issue #149189 · python/cpython
Description: Feature or enhancement Proposal: Python 3.15 introduces the expand keyword for pprint, which improves the output: expand (bool) – If True, opening parentheses and brackets will be followed by a newline and the following content will be i...
Open Graph Description: Feature or enhancement Proposal: Python 3.15 introduces the expand keyword for pprint, which improves the output: expand (bool) – If True, opening parentheses and brackets will be followed by a new...
X Description: Feature or enhancement Proposal: Python 3.15 introduces the expand keyword for pprint, which improves the output: expand (bool) – If True, opening parentheses and brackets will be followed by a new...
Opengraph URL: https://github.com/python/cpython/issues/149189
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Modern defaults for `pprint`","articleBody":"# Feature or enhancement\n\n### Proposal:\n\nPython 3.15 introduces the `expand` keyword for [`pprint`](https://docs.python.org/3.15/library/pprint.html), which improves the output:\n\n\u003e * **expand** (_bool_) – If `True`, opening parentheses and brackets will be followed by\n\u003e a newline and the following content will be indented by one level, similar to\n\u003e pretty-printed JSON. Incompatible with _compact_.\n\nFor example, this code:\n\n```python\nfrom pprint import pprint\n\nconfig = {\n \"database\": {\n \"host\": \"db.example.com\",\n \"port\": 5432,\n \"options\": {\n \"connect_timeout\": 5,\n \"pool_size\": 10,\n \"ssl\": True,\n \"sslmode\": \"verify-full\",\n },\n },\n \"logging\": {\n \"level\": \"INFO\",\n \"file\": \"/var/log/app.log\",\n \"handlers\": {\n \"console\": {\"enabled\": True},\n \"file\": {\"rotate\": True, \"max_bytes\": 1048576},\n },\n },\n}\n\nprint(\"===== expand=False =====\")\nprint()\npprint(config)\n\nprint()\n\nprint(\"===== expand=True =====\")\nprint()\npprint(config, expand=True)\n```\n\nProduces:\n\n```\n===== expand=False =====\n\n{'database': {'host': 'db.example.com',\n 'options': {'connect_timeout': 5,\n 'pool_size': 10,\n 'ssl': True,\n 'sslmode': 'verify-full'},\n 'port': 5432},\n 'logging': {'file': '/var/log/app.log',\n 'handlers': {'console': {'enabled': True},\n 'file': {'max_bytes': 1048576, 'rotate': True}},\n 'level': 'INFO'}}\n\n===== expand=True =====\n\n{\n 'database': {\n 'host': 'db.example.com',\n 'options': {\n 'connect_timeout': 5,\n 'pool_size': 10,\n 'ssl': True,\n 'sslmode': 'verify-full',\n },\n 'port': 5432,\n },\n 'logging': {\n 'file': '/var/log/app.log',\n 'handlers': {\n 'console': {'enabled': True},\n 'file': {'max_bytes': 1048576, 'rotate': True},\n },\n 'level': 'INFO',\n },\n}\n```\n\n\"Prettiness\" is subjective, but in my opinion, the expanded output looks nicer and is much easier to read. It's also closer to code formatted with modern tools like Black and Ruff.\n\n## Opinions about `pprint`\n\nOthers also don't like the current default:\n\n\u003e For a long time I was unhappy with default values that standard pprint module has\n\u003e (`from pprint import pprint`). So, I decided to change them as I like and not pass\n\u003e them every call to pprint.\n\nhttps://alex-ber.medium.com/my-pprint-module-f25a7b695e5f\n\n\u003e However, it has a very greedy layout algorithm that fails to produce pretty output in\n\u003e many cases.\n\nhttps://tommikaikkonen.github.io/introducing-prettyprinter-for-python/\n\n\u003e `pprint++`: a drop-in replacement for `pprint` that's actually pretty ... Why is it\n\u003e prettier? Unlike `pprint`, `pprint++ strives to emit a readable, largely\n\u003e PEP8-compliant, representation of its input.\n\nhttps://github.com/wolever/pprintpp\n\n\u003e the current output for a large nested dictionary with pprint is basically unusable and\n\u003e definitely not pretty, which is a shame because large dictionaries are probably the\n\u003e primary use case for pprint.\n\nhttps://github.com/python/cpython/issues/112632#issuecomment-2597056481\n\n\u003e When working with deeply nested dictionaries (depth 4+), readability becomes critical.\n\u003e Python’s built-in `pprint module is the default choice for \"pretty printing,\" but it\n\u003e often falls short with deep nesting—producing cluttered, inconsistently indented\n\u003e output that’s hard to parse.\n\nhttps://www.pythontutorials.net/blog/how-to-pretty-print-nested-dictionaries/\n\n\u003e I don't really fancy the way Python's pprint formats the output. [...] But I'd like it\n\u003e to be [...] in the style of Black\n\nhttps://stackoverflow.com/questions/69945869/pretty-printing-python-dictionary-lists-in-black-style\n\n## Other tools and workarounds\n\nThe formatting can be improved by using third-party libraries, for example, `rich.print()`, and `pprintpp` and `alexber.utils.pprint` mentioned above. Or by changing the defaults yourself, or following an oft-recommended and somewhat roundabout `print(json.dumps(d, indent=4))`.\n\nBut `pprint` is often used for debugging because it's always within arm's reach: you just want to `import pprint as pprint` and `pprint(my_var)`.\n\nTherefore, I believe it would be beneficial to modernise `pprint`'s defaults:\n\n| argument | before | after |\n| -------- | ------- | ------ |\n| `expand` | `False` | `True` |\n| `indent` | `1` | `4` |\n| `width` | `80` | `88` |\n\n## `pp()`\n\n[`pp()`](https://docs.python.org/3/library/pprint.html#pprint.pp) was [added to 3.8 in 2017](https://github.com/python/cpython/issues/74855). It's the same as `pprint()` but with `sort_dicts=False`.\n\nThis is from the discussion preceding its addition, which considered changing the `pprint()` default:\n\n\u003e \u003e I guess the underlying issue here is partly the question of what the pprint module\n\u003e \u003e is for. In my understanding, it's primarily a tool for debugging/introspecting\n\u003e \u003e Python programs, and the reason it talks about \"valid input to the interpreter\"\n\u003e \u003e isn't because we want anyone to actually feed the data back into the interpreter,\n\u003e \u003e but to emphasize that it provides an accurate what-you-see-is-what's-really-there\n\u003e \u003e view into how the interpreter understands a given object. It also emphasizes that\n\u003e \u003e this is not intended for display to end users; making the output format be \"Python\n\u003e \u003e code\" suggests that the main intended audience is people who know how to read, well,\n\u003e \u003e Python code, and therefore can be expected to care about Python's semantics.\n\u003e\n\u003e pprint.pprint() is indeed mostly for debugging, but not always. As an example of what\n\u003e will break if you change the sorting guarantee: in Mailman 3 the REST etag is\n\u003e calculated from the pprint.pformat() of the result dictionary before it’s JSON-ified.\n\u003e If the order is changed, then it’s possible a client will have an incorrect etag for a\n\u003e structure that is effectively the same.\n\nhttps://mail.python.org/archives/list/python-dev@python.org/message/UYMINUYHZ3O7B2DKXI7B2T42TYCJFZ3N/\nhttps://mail.python.org/pipermail/python-dev/2017-December/151403.html\n\nI agree changing `sort_dicts` changes the _code_ output.\n\nBut _display_ output is different and is safer to change: parsing the output will get you the same thing. As long as you're not doing brittle character-level parsing, it's essentially the same Python code.\n\n\n## Alternatives\n\nI'm also open to:\n\n- Only change defaults for `pp` (similar to [this suggestion](https://discuss.python.org/t/the-pprint-module-should-use-the-terminal-width-where-available/27658/3))\n- Add a new function with these defaults, somewhat similar to `pp`\n- Perhaps a new keyword to define a new style, that would override these defaults\n\n\n### Has this already been discussed elsewhere?\n\nNo response given\n\n### Links to previous discussion of this feature:\n\n_No response_\n\n\u003c!-- gh-linked-prs --\u003e\n### Linked PRs\n* gh-149190\n* gh-150249\n* gh-150268\n\u003c!-- /gh-linked-prs --\u003e\n","author":{"url":"https://github.com/hugovk","@type":"Person","name":"hugovk"},"datePublished":"2026-04-30T15:55:49.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":12},"url":"https://github.com/149189/cpython/issues/149189"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:ff6db97f-69a8-b34b-2974-114cb615147d |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | EBF0:1ECA58:A9F5C5:E23D9D:6A52B8DC |
| html-safe-nonce | e4898ba0ed8d4ae9e6aed221de27a80415aa83bf3b2256873ad6c2bd0cdd41e8 |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJFQkYwOjFFQ0E1ODpBOUY1QzU6RTIzRDlEOjZBNTJCOERDIiwidmlzaXRvcl9pZCI6IjUyMDcwMzcyNDg3Mzc1ODk0MCIsInJlZ2lvbl9lZGdlIjoiaWFkIiwicmVnaW9uX3JlbmRlciI6ImlhZCJ9 |
| visitor-hmac | 9ffb4143211514afdb09cfb6c26c083c50fbab2d19b6e292ae2f592073b8de26 |
| hovercard-subject-tag | issue:4359473853 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/149189/issue_layout |
| twitter:image | https://opengraph.githubassets.com/ea54f72ed15a81996eef40d055fe8be4848c4918028cc00fa67cdee06b76bbc3/python/cpython/issues/149189 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/ea54f72ed15a81996eef40d055fe8be4848c4918028cc00fa67cdee06b76bbc3/python/cpython/issues/149189 |
| og:image:alt | Feature or enhancement Proposal: Python 3.15 introduces the expand keyword for pprint, which improves the output: expand (bool) – If True, opening parentheses and brackets will be followed by a new... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | hugovk |
| hostname | github.com |
| expected-hostname | github.com |
| None | b9a586c06a05a7a86fc7e3f4dbd03e42f6869085879aa184aa6369456dbd50fb |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 07a982c1d40157c619b364352b704c3ce66bb332 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width