I would like to reiterate a point that I think is very important and many people seem to be brushing aside. We don't have to *break* existing code. We can get a lot of value, at least in terms of aiding debugging, just by adding a warning. That warning never has to evolve into an exception, certainly not anytime soon. The most damage it would do is some clutter in stderr, and that would only be for some time while libraries adapted. People add deprecation warnings all the time.
Consider again the example of taking the boolean of a numpy array or pandas Series. That certainly broke some existing code. And it broke consistency where bool() is usually determined by len(). But most importantly, it was a reversible change. Right now, the maintainers could look at the community reaction and decide to make bool(array) work again as expected, or maybe in a new way. Doing so wouldn't break any working code because no working code uses bool(array). But they have chosen not to, presumably because they believe the current behaviour is still for the best. So here's what I take from all this:
1. The 'experiment' to force users to state their intentions explicitly to avoid subtle logical bugs is deemed a success.
2. If our 'experiment' failed and users were really offended by seeing warnings, we could undo it. We'd leave chars() behind as a noop. No code would be broken by the reversal. So the extent of the damage in the worst case scenario would be even more limited. You might complain that now there'd be two ways to iterate over characters, but similarly I always choose to add .keys() when I iterate over a dict even though it's redundant, because it makes the code clearer.
3. Regarding a point made by Chris: introducing the error in bool() is considered OK even though it's sometimes hard to see where bool() is being used, such as when a user writes `df[0 < df.val < 1]` which is the equivalent of `df[0 < df.val and df.val < 1]` when they want the behaviour of `df[0 < df.val & df.val < 1]`.