And this is precisely what I was pointing out - the pretty argument is at the wrong granularity, you don’t want every argument to be pretty printed in this case (and I’d argue, in every case where a literal string is one of the print arguments).
Also, if some of the arguments are large enough that pretty printing them takes multiple lines, concatenating the pretty-printed representation of the individual arguments is likely to result in bad line breaks:
>>> long = [12345] * 20
>>> short = [1] * 8
>>> print("Long =", pformat(long), "and short =", pformat(short))
Long = [12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345,
12345] and short = [1, 1, 1, 1, 1, 1, 1, 1]
It’s not terrible, but it’s not ideal, and it’s very data dependent how good it is.
What I’m trying to say is that I’m not sure that an option which works well for a single positional argument, and sort of works in some cases for multiple arguments, but in many multiple-argument cases gives suboptimal results, is good enough to be made part of the language spec.
Conversely, the !p conversion specifier is at the right granularity - it modifies how precisely one value is formatted.
I disagree. Making the functionality of the pprint module more accessible doesn’t in itself make it “fully built in behaviour”. It’s still just as possible to change and improve the behaviour of the pprint module, and that will be reflected in the built in behaviour. (As a side note, the PEP should be clear on how the !p conversion spec will be affected if someone were to monkey-patch or otherwise replace the stdlib pprint module - it would be a really odd special case if doing so didn’t change the behaviour of !p).
What’s more questionable is the __pprint__ protocol. And I think that’s where we need to be careful. If we treat __pprint__ as nothing more than an enhancement to the pprint module, using a dunder not as a language-level protocol but as an implementation mechanism for the stdlib module (much like object.__copy__ is an implementation detail of the copy module), then it remains “behavior [which] is encapsulated and local to that module”. That’s fine, but we’ve now started to look at enhancing the pprint module - and if we’re doing that, we can’t really argue that including features like customising the display of builtin types, or supporting custom container formatting, is “out of scope”. And at the very least, a __pprint__ protocol that isn’t designed in a way that can be extended in the future to such use cases, is a potential backward compatibility issue when we do want to look at them. While that doesn’t make the protocol a language-level behaviour, it does mean that it introduces many of the same concerns that language-level changes have.
So while I disagree with your claim that the PEP makes pprint a “built-in behaviour”, I do think that it makes pprint a much more important part of the stdlib, and as a consequence, we need to be more careful about the implications - right now, changing pprint is a fairly low-impact matter, but if we make the behaviour of print and the !p conversion specifier depend on it, such changes become a lot more significant.