CLN: use f-strings where possible
- [x] [Tests added and passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#writing-tests) if fixing a bug or adding a new feature
  - No new tests, behavior hasn't changed (except possibly become a bit faster)
- [x] All [code checks passed](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#pre-commit).
- [x] Added [type annotations](https://pandas.pydata.org/pandas-docs/dev/development/contributing_codebase.html#type-hints) to new arguments/methods/functions.
  - Nothing new.
- [x] Added an entry in the latest `doc/source/whatsnew/vX.X.X.rst` file if fixing a bug or adding a new feature.
  - No bug or feature, just cleaning.

---

This PR replaces a bunch of string concatenations and other non-modern formatting operations with f-strings. 

The first commit was done mechanically with [`flynt`](https://github.com/ikamensh/flynt), followed up by further manual touch-ups that `flynt` wasn't smart enough to touch.

This does _not_ touch a bunch of concatenations in `pandas/io/stata.py`, since those are covered by cln commits in #49228.
Hi @MarcoGorelli, thanks for the review. I remade this PR to limit the scope to non-test files – the test failure was caused by `flynt`'s aggressive string concatenation mode changing things it shouldn't have there.

In addition, I took extra care to only mechanically run safe transforms, and then applied other select fixes by hand in the subsequent commits. 

The PR now touches 47 files instead of 120, and the changes are all practically 1 line here and there. Also, we already have pyupgrade for rewriting f-strings when it's safe to do so

Closing for now then, but thanks for your PR @MarcoGorelli I would ask you to reconsider. This PR isn't really done by an automated tool anymore. I used `flynt` as a guide, as it were, and checked and improved the changes it suggested by hand. The issue with adding mostly cosmetic changes without an automated tool is that there's no way to ensure contributors won't new code that goes against these changes, and then we'll be here again in a month's time making the same changes manually

But if there's a case where this makes a performance difference at the macro level, then happy to take that- e.g. the change you mentioned here https://github.com/pandas-dev/pandas/pull/49229#discussion_r100247531 > The issue with adding mostly cosmetic changes

These aren't really only cosmetic changes.

> without an automated tool is that there's no way to ensure contributors won't new code that goes against these changes

As far as I understand, all PRs to Pandas are reviewed by humans too.  
That reviewing human would probably go "Hey, couldn't you use `f"^{foo}"` instead of `"^" + str(foo)`" (or similar).

Again, these changes have been made by a human (yours truly), not an automated tool. Would the context of the review be different if I had not originally mentioned a tool? These kinds of changes should be made by automated tools without requiring manual fixups, so that
- we can add this to CI
- we don't need to keep leaving comments in PR reviews about them

If it's done manually, then we'll be doing it manually again in a month's time, and then again, and so on I'm sorry, but can you explain what "these kinds of changes" are? 

These changes hadn't, and couldn't have, been made automatically by a tool in CI because no tool currently exists that could do the semantic/dataflow analysis to see whether a concatenation can be safely replaced with an f-string.

Fortunately, humans _can_ do that, and as said in my comment after the first test failures, I manually, by hand, vetted each change recommended by `flynt`. Ah, darnit, apparently trying to rebase/force-push a closed PR destroys things and this can't be reopened anymore.

Considering the discussion above, would you be open to re-reviewing a PR if I open a new one, @MarcoGorelli? I honestly believe these changes are objectively _good_ and could have been done earlier by humans, but it just hadn't happened. I just meant mostly cosmetic / stylistic changes - if any of these delivers a measurable performance improvement, then sure, feel free to submit a PR

If there's no performance improvement and it can't be rewritten/checked automatically, then I'm not sure there's much reason to make the change @MarcoGorelli Would https://twitter.com/raymondh/status/1205969258800275456 (found via the https://pylint.pycqa.org/en/latest/user_guide/messages/convention/consider-using-f-string.html doc page) be enough proof that f-strings will deliver performance improvements even in the simple cases? that tweet shows savings of a few nanoseconds -if there's some pandas operation where concatenating strings compounds and there's a noticeable performance improvement overall, then that's great - your sql.py example might be a good example of this. if it's just an error message that'd only be printed once, then I'd say this isn't worth the churn Well, to put the tweet in other terms, it shows improvements of 32% to 300% for a simple operation.

What's the downside of "churn" for an improvement and how do Pandas developers quantify when it's worth it or not? 

Also, I'd like to point out that this isn't the first PR to just change things to f-strings because it's possible; has something changed since https://github.com/pandas-dev/pandas/issues/29547?