The changes are trumpeted as easier for newcomers to learn. Let's see - a newbie decides to fetch an URL with some text content. The fine manual does explain that you will obtain bytes and must decode them but then goes full cargocult "we know uses utf-8 so just decode it as utf-8." No further discussion about detecting encodings, resolving inevitable errors,.. Their example will bomb out if the read(100) return value ends with incomplete UTF-8 character. In short, no canonical information is provided How To Correctly Fetch An Text URL Into A String. Not even some small convenience function that at least tries to look on Content-Type: header!

In py2k the urlopen() just worked 99% of time without further ado - unless you were doing involved text transformation or depended on exact character counts, it was fine. In py3k you are forced to do lossy conversion and deal with the fallout, even risking easy denial of service if you don't catch all cases right. And that for most basic of uses, like this cat example. Honestly, is this an improvement?