> In Python 2, you have one class, string, which is performing two different jobs.

What? Have you used Python 2? No: in Python 2, you have two classes; one is called "str" and represents a sequence of bytes, and one is called "unicode" and represents text. The former is used while interacting with network protocols and files, and the latter is what you use internally in your program: at the boundaries you use .decode and .encode to convert using character encodings. (BTW: Python 3 actually got this wrong for years, and even now I think it is only fixing the problem with a mitigation :/ filenames do not have an encoding: they should be of type "bytes", not of type "unicode", and Python 3 seriously shipped with an implementation of "list files in directory" which returned names as "unicode" and any names which failed to convert were just skipped.)

Then, Any text in your program should use a syntax u"" to indicate it is program text of type unicode. Sure: there are some really annoying implicit conversions in place that allow mistakes to be made, but WTF: they absolutely didn't need to rename "str" to "bytes" and "unicode" to "str" while simultaneously not only changing tons of other things in the language (the ability to pick and choose is amazing for porting) and making pointless related changes like removing the u"" syntax (which yes, I realize they added back later... years later... many many years too late). They should have just given me a way to "poison" str/unicode objects so they refuse to participate in implicit conversions, which would have let me find the corner cases in the libraries I use that are doing things wrong so I can report them to their maintainers and get them patched; after a couple years of people throwing .poison in a bunch of places users would have been ready to flip a VM-level "just don't convert them anymore".

As for renaming the classes, "bytes" should have been left as an alias for "str" (as it was/is "temporarily"/forever in Python 2.7), "str" should have generated a warning... I mean, "str" isn't even a good name :/... it's a silly three character abbreviation of a concept that is ambiguous in the minds of most developers already due to other languages, whether they be like C or JavaScript). They certainly had absolutely no good reason to get rid of the "unicode" type name (and this one still isn't back). The set of decisions they made were so annoying that even people who know what they are doing have to do a ton of fidgety and easily-broken work in a dynamically typed language where you are more than likely to just break something and not realize it until a month later.

Seriously: I've been programming in Python (2, not 3000) since 2007 as one of my primary programming languages; I do all of my web development in Python, for a website which is used around the world by millions of people and is not only itself translated into tons of languages (by both professionals and volunteers) but deals with tons of user-generated content that is accessed via tons of different channels (APIs from various websites, native network protocols, and tons of file formats as all the content indexing is also written by my, in Python), and dealing with these issues in Python 2 is simply a non-issue: in fact, I would say it is almost trivial (and in fact, the ways it tends to break in Python 2 are often quite similar to the way things break in Python 3, as it is easy to set up situations where the implicit conversions essentially fail).