Python 2.8?
Python 2.8?
Posted Jan 13, 2017 6:48 UTC (Fri) by Cyberax (✭ supporter ✭, #52523)In reply to: Python 2.8? by ddevault
Parent article: Python 2.8?
I don't care what you call them. The real world out there is not unicode, it is composed of strings of bytes.
Python 3 made working with them extremely cumbersome.
> It's fair to argue that Python 3's choice to break backwards compatability was a mistake, but it's not fair imo to criticise the current design.
Yes it is fair. Python 3 unicode design is totally braindead. We now have several examples of GOOD unicode-enabled design, from both parts of the spectrum:
1) Perl 6 dove deep and encodes strings in the NFG, thus making string operations intuitively correct. It won't split words between combining characters, for example. Python 3, of course, is completely clueless about that.
2) Go treats strings as arrays of octets. Always. It also has handy functions to manipulate arrays of octets that happen to be UTF-8 encoded texts.
Sorry. But Py3 is not well-designed, it's a great example of a "second system effect". The fact that companies are migrating from Py27 to Golang should give Py3 developers some clue.
Example from this thread:
1) Set up:
>>> open('test-\ud800.txt', 'w').close()
2) Python 2.7 (works as expected):
>>> [open(f, 'r').close() for f in os.listdir(b'.')]
>>> [None]
3) Python3.5 (craps its pants):
>>> [open(f, 'r').close() for f in os.listdir(b'.')]
>FileNotFoundError: [Errno 2] No such file or directory: b'test-\xed\xa0\x80.txt'
So, why should I migrate to Py3 if it's full of stuff like this? What's the point?
Posted Jan 13, 2017 7:01 UTC (Fri)
by ddevault (subscriber, #99589)
[Link] (5 responses)
_Strings_ are NOT bytes. They are characters. Python 3 strings are arrays of characters, and bytes are just that - bytes. Bytes are not strings. Bytes are bytes. A "string of bytes" isn't a phrase that makes sense. Bytes in Python 3 is a byte array. That's all that it is. Period. End of discussion. It could be a byte array whose contents is an _encoded_ string, which you might decode into an array of characters (aka a string). But it's NOT a string.
>Python 3 made working with them extremely cumbersome.
No, it made it wonderfully simple. You're just using it wrong.
Your example is also broken.
>open('test-\ud800.txt', 'w').close()
You're already off to a bad start. Did you even try your example in Python 3?
>>> open('test-\ud800.txt', 'w').close()
Let me show you what you meant to do:
>>> open(b'test-\ud800.txt', 'w').close()
Note how it doesn't crap out. You need to get your head out of Python 2 and learn Python 3 properly.
Posted Jan 13, 2017 7:20 UTC (Fri)
by Cyberax (✭ supporter ✭, #52523)
[Link] (4 responses)
> But it's NOT a string.
Why should "real strings" be special?
> No, it made it wonderfully simple. You're just using it wrong.
> You're already off to a bad start. Did you even try your example in Python 3?
> Note how it doesn't crap out. You need to get your head out of Python 2 and learn Python 3 properly.
If I jump through all the hoops - what do I gain as a result? Nothing but headache. Unicode support in Python3 provides no usefulness whatsoever.
Posted Jan 13, 2017 7:26 UTC (Fri)
by ddevault (subscriber, #99589)
[Link] (3 responses)
Posted Jan 13, 2017 7:39 UTC (Fri)
by Cyberax (✭ supporter ✭, #52523)
[Link]
BUT THIS IS NOT TRUE!
Real world out here is full of misencoded stuff that can only be represented by byte arrays. It can NOT be encoded into strings without losses or quoting. Thus "PathLike" class with dual nature to represent them is needed for Py3.
Py3 makes working with such entities a total pain. Py27 is entirely a breeze - it just works.
And please, do explain what I gain from following all the Py3 rules of unicode strings? What are the advantages over Py27 with utf-8 strings?
Posted Jan 13, 2017 17:42 UTC (Fri)
by sfeam (subscriber, #2841)
[Link]
Posted Jan 14, 2017 15:36 UTC (Sat)
by bronson (subscriber, #4806)
[Link]
You're saying that there are lots of problems with Python 3?
Posted Jan 19, 2017 10:28 UTC (Thu)
by chojrak11 (guest, #52056)
[Link] (1 responses)
You're grossly wrong. There are many rationales for the migration, none of them being wrong Unicode design in Python. Some of them are:
1) Poor Python performance, caused by runtime type reconciliation because of
Go is fast, because it's staticly typed language. There's no risk that a method will be called with unplanned data type, because compiler does the hard work with its type system. Thanks to that less unit testing is required and that, in turn, allows for faster feature delivery.
Posted Jan 20, 2017 16:49 UTC (Fri)
by NAR (subscriber, #1313)
[Link]
Posted Jan 19, 2017 14:45 UTC (Thu)
by anselm (subscriber, #2796)
[Link] (4 responses)
That's not what happens on my machine (which is running Debian Stretch):
Looks reasonable to me. In any case Python 3.5 doesn't seem to have a problem dealing with file names that are byte strings. (Trying to retrieve the file name as as (Unicode) string doesn't work but then again the file name isn't valid UTF-8-encoded Unicode to begin with, which I guess was part of the original point.)
Generally I've been quite happy with Python 3 so far. I have yet to run into something that would tempt me to go back to Python 2.7, or for that matter a hypothetical Python 2.8.
Posted Jan 19, 2017 16:49 UTC (Thu)
by excors (subscriber, #95769)
[Link] (3 responses)
Paths on Linux are sequences of arbitrary 8-bit symbols, so byte strings work trivially there (as long as you don't assume they're e.g. UTF-8). And Python's Unicode strings work okay for paths on Windows since no conversion is needed. But it's a pain when you're trying to write code to run on both platforms - you either pick one type of string and suffer with error-prone conversions on the other platform, or you create a new opaque native-path type with explicitly lossy conversions to the standard string type (like Rust's OsString).
Posted Jan 19, 2017 23:22 UTC (Thu)
by anselm (subscriber, #2796)
[Link] (2 responses)
Am I glad I don't have anything to do with Windows. Having to use Windows must really suck.
Posted Jan 22, 2017 2:03 UTC (Sun)
by flussence (guest, #85566)
[Link] (1 responses)
Posted Jan 22, 2017 10:25 UTC (Sun)
by mathstuf (subscriber, #69389)
[Link]
Posted Jan 27, 2017 1:26 UTC (Fri)
by ras (subscriber, #33059)
[Link] (2 responses)
> >>> open('test-\ud800.txt', 'w').close()
Well you were right it doesn't work in 3.5, but it does so in an entirely reasonable way. This was not true in earlier versions.
> The real world out there is not unicode, it is composed of strings of bytes.
Actually, the real world has both strings and bytes. Strings are things you can display to a human. You can not reliably display bytes. A type system the distinguishes between the two reduces the odds of displaying unintelligible crap to users.
The distinction was unnecessary when ASCII was the sole encoding. Even after that it wasn't a pressing issue when the only people likely to see your strings were in the same office. But then the internet came along, and the solution we had adopted was to represent printable strings as the tuple (encoding, bytes) - and there were 100's of encodings. Agreeing on an encoding when you are all in the same office is one thing, but negotiating a common encoding between two remote systems so they can exchange strings was unworkable.
Unicode was meant to fix it, but initially it didn't. Amazingly, it appears they failed to understand the problem because they gave us multiple encodings for Unicode. Fortunately a C programmer came along, gave us UTF-8 which the world has settled on. Somewhat less fortunately early systems (Java, Windows) have adopted the failed earlier attempts at encoding Unicode. Python 3 has avoided that mess - it's internal representation looks pretty good to me.
Python 3's biggest mistake, which as you point out they still haven't recovered from, is they didn't abandon making "open('name', 'rt')" the default. The core problem is what 't' means isn't well defined on Unix (whereas "open(b'name', 'rb')" is always well defined). In fact it was never well defined - line endings have always varied between systems. But extending 't' to define the encoding broke it completely because it no longer just effected line endings - it was the whole document, and the file names that pointed to it. Worse, assuming 't' on file handles that transport bytes (like many pipes and sockets) meant they failed to work at all whereas before they did.
But the solution is easy enough. In python3, get into to habit of treating casting all file names to bytes, opening all files in binary, and doing the conversations yourself - which is how it should be done. You will find this hugely annoying, as there will be many times you won't know what encoding to use. But in that case you will be able to put the blame where it belongs - which on whoever wrote the data, not python3.
For files that should be printable ASCII (eg, most config files in /etc) I find "open('...', encoding='ascii', errors='ignore')" a reasonable way to pretend the world hasn't changed in 30 years.
Posted Jan 27, 2017 23:40 UTC (Fri)
by lsl (subscriber, #86508)
[Link]
That's certainly how Python 3 approaches it but is not something universally agreed upon in the field. I like to think of strings as just that, a sequence of …things (bits, bytes, "characters", whatever kind of symbol you can come up with).
Ok, so the Py3 string type doesn't represent a generic string but is a type tailored to the use-case of displaying text to users. That's fine. What's not fine is how it permeates all kind of APIs in the Python standard library that don't have anything to do with displaying text to users and might even be incompatible with it, requiring lots of weird workarounds for things that just work with Python 2.
That's kinda of what was meant by Python 3 throwing system programmers under the bus for the benefit of high-level "app" developers. That's certainly a decision one can make but there shouldn't be any surprise that not everyone likes it.
Posted Jan 28, 2017 0:09 UTC (Sat)
by lsl (subscriber, #86508)
[Link]
In my opinion, the actual mistake is the inclusion of such "text" mode for file I/O in the first place. It doesn't have a place in a modern language designed for modern computers.
Even decades ago it reeked of design-by-commitee, probably driven by mainframe vendors who (from today's perspective) did ultra-weird things with text vs. non-text (and "file" I/O in general). Back then it was probably a reasonable argument that a general-purpose language should support stuff like this. But today? Virtually all operating systems settled on the same "bag of bytes" file abstraction. Even those who didn't either run Python in a POSIX-like environment or don't run it at all (and probably never will).
There's no reason left to justify the complication of file I/O with this "text vs. binary" stuff. Just as a modern file transfer protocol wouldn't include a "tenex" mode-switching command.
Python 2.8?
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
UnicodeEncodeError: 'utf-8' codec can't encode character '\ud800' in position 5: surrogates not allowed
>>> [open(f, 'r').close() for f in os.listdir(b'.')]
[None]
Python 2.8?
No, they aren't. They are NOT arrays of characters, and anybody who is familiar with Unicode can tell you that. Python strings are arrays of Unicode _codepoints_ - a Unicode character can _easily_ consist of multiple codepoints.
I don't CARE about strings. Py3 "strings" are an exception in the REAL world out here. Real world operates on byte sequences - they are in HTTP headers, in CSV files, in filenames and so on.
"You're holding it wrong" - exactly.
Yes, I did. It's an example from: https://lwn.net/Articles/711492/ - on Windows, though I think I've used 'test\x01\x02.txt'.
Thanks, but I don't like Koolaid.
Python 2.8?
Python 2.8?
"Development would be so easy if it weren't for those pesky users."
Python 2.8?
Python 2.8?
Python 2.8?
2) Dynamic typing, which then requires
3) Lots of unit tests required to keep that dynamic types in shape.
Python 2.8?
Python 2.8?
$ python3.5
Python 3.5.2+ (default, Dec 13 2016, 14:16:35)
[GCC 6.2.1 20161124] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import os
>>> [open(f, 'r').close() for f in os.listdir(b'.')]
[None]
>>> os.listdir(b'.')
[b'test-\xed\xa0\x80.txt']
Python 2.8?
Python 2.8?
Python 2.8?
Python 2.8?
Python 2.8?
> UnicodeEncodeError: 'utf-8' codec can't encode character '\ud800' in position 5: surrogates not allowed
Python 2.8?
Python 2.8?