I don't like that Python took the "stream of bytes" approach. It's supposed to be a high level language.
Having said that, Unicode is an ungodly mess.
Back in the days, you had 8 bits characters, nice and easy. Problem: you can't fit a lot in 256 values.
Allright, then, let's use 16 bits, that's enough. That was the case when Java decided to go with 16 bits chars. It did have a serious performance penalty: if you were dealing with ascii, your throughput was halved. But it did preserve the efficient random access semantics. In spite of the performance penalty, it feel it was the right choice at the time.
Except Chinese speakers complained because you couldn't fit all traditional chinese characters in Unicode. Only simplified ones. And, in fairness, they had a point. Unicode was meant to represent _every_ character.
So suddenly the character set was expanded beyond 65536, which made the 16 bits the _worst_ choice. Some "characters" had to be split into two codepoints. All the inconvenients of having multi-"characters" characters, all the inconvenients of large characters to begin with, without the advantages of efficient random access.
So now, you can either have an API that has 4 byte characters (easy to use but dreadfully inefficient), UTF8 (efficient but painful to use in some cases), or just bytes (efficient but painful to use in other cases)(or more correctly, "not my problem, best of luck", quite the acceptance of inability from people whose job it is deal with just that).
It's really a case of picking your poison.