Key differences between Python 2.7.x and Python 3.x (2014)
sebastianraschka.com
sebastianraschka.com
I would like to consider python for my next project, but this is extremely short sighted advice which begs the very real question: why should I consider python at all for a new, multi year project when there is no clear path forward for the language and there hasn't been in a decade?
Also, how can you ask someone who is new to the language to just choose? To me that seems insane. They have nothing to base their choice on, yet this choice will decide the future and success of the app. No pressure. But to be honest, and I know this is not the community's intention, the python 2/3 split is about as unwelcome a reception to a programming language as I can imagine. Is there a more logical way to choose?
Finally, I've now seen clients demand rewrites of python 2 code because of (probably bullshit) concerns around its obsolescence and lack of security. Now these clients generally don't know python from their ass and I doubt they have valid technical concerns but as invalid as their concerns probably are, it's still a major issue of your big clients threaten to leave unless you rewrite all your python 2 to 3. Anyone faced this?
It should probably be updated to say that unless you have a VERY strong reason to use 2.7, use 3. And even then, probably still use 3, because your reasons probably aren't as strong as you think they are.
EDIT: Generally the strong reasons most people had for using py2.7 for new projects were some variant of: "X, Y and Z libraries I need only support 2.7". But now and days, that actually stands as more of a reason to find alternate libraries.
- code that has to run on HostGator shared hosting. They only support Python 3.2, the "maximally incompatible" version.
- code that has to run on ROS, the Robot Operating System. ROS is a huge collection of packages from various sources glued together by a message passing system. Efforts to convert all those packages to run under Python 3 have been underway for years, but aren't done yet.
In those cases, one can, without too much effort, write forward-compatible python 2 code at least.
I learned Python from Python 3, and it hasn't hindered me at all, even from going back and working on Python 2 code bases, or cross compatible code bases. It's a perspective that's made me just how aware of how awful Python 2 is in comparison.
Python 2 is going to exist for a long time in a lot of places. But it's a dead end for improvements. It's a dead end for innovation. It's a dead end for bug fixes and security fixes. Would you even consider telling someone to go learn any other language that is 3 years away from even end of life support having the plug pulled? You wouldn't. Why would you do the same for Python 2?
One the one hand I have this from you, an anon as far as I'm concerned. On the other I have Google, filled with some of the world's best python developers (and until recently the BDFL Guido van Rossum himself). Google App Engine still doesn't support Python 3.
Um, yes it does: https://cloud.google.com/python/quickstarts
Python 2's official support ends in 2020.
How can you ask someone new to the language to just choose? Well they don't have to choose. They just choose Python 3. That's what it says on the Python website. It's what everyone in the community says.
Do you need to use packages that only support Python 2 and there are no alternatives? Use Python 2.
Otherwise? Use Python 3.
If someone doesn't know whether they should be using 2 or 3, they should be using 3.
It would seem that the article is out of date and there is now a clear path forward. However, I think that we also see here a problem with the BDFL model of programming language governance. Unless Python 3 is somehow well over 2X times more productive than Python 2, I don't see the amount of disruption caused by the change as having been worth it. Is that the case?
You could argue that the reason folks didn't adopt 3.x quickly was that the core devs stayed committed to 2.x.
It's standard practice for software maintenance to work on both the old version and the new fork for a while, giving users a chance to switch. Look at how Microsoft manages versions of Windows. I think the Python devs stand out in their willingness to work on both versions for so long.
I'm not a particularly advanced user of python (seriously, just ops scripts), but it looks like it's basically 'all sticks' to me. I've heard people grateful about better unicode handling, but not much more than that.
What does a "clear path forward" mean in the context of a programming language? In what way does python not have one?
>yet the choice will decide the future and success of their app
No it won't. I would argue that programming language choice generally has little effect on success, but it has even less effect when the languages are as similar as python 2 and 3.
>rewrites of python 2 code
Hardly a rewrite, I presume. They would need to change their syntax in some places, change package names in others, and any place they've dealt with strings might require some fiddling, but overall it would be relatively easy. Much easier than a rewrite at least.
You don't have to choose. For new projects, Python 3 has been the way to go for many years now[1][2].
[1] PSF wiki guidelines https://wiki.python.org/moin/Python2orPython3
[2] Snapshot of the same page from 2011, clarifying that "Python 3.x is the present and future of the language": https://web.archive.org/web/20110902011248/http://wiki.pytho...
The reason is async/await. It can handle Node.js style event loop / asynchronous code very well -- with uvloop, python 3.5+ is actually faster than Node.js (close to Go).
https://magic.io/blog/uvloop-blazing-fast-python-networking/
IMHO: after 3.5, we are clearly in the next iteration of the language.
Uhhh I call BS until proven otherwise. Maybe the event loop is faster, but I'm willing to bet the callback code is slower.
This is exactly the case, and the slowdown is pretty noticeable IMO. Still, python 3 is a whole lot better at this than python 2.
Please don't play the "it depends" card just to be smug. It lowers the level of discourse.
JIT-ed code can be pretty fast, but so can calls to libraries like NumPy. PyPy can also be somewhat speedy, though it hasn't had as much dev time as v8. And if you somehow find yourself breaking new ground with an algorithm no one's written a fast implementation of yet, there's always Cython.
Besides, if there's any task that takes more than a negligible amount of time, I usually push it to a different process and respond immediately. The callback speed in that case is bound by the time it takes to write to a message queue or append to a database table, not the language itself.
This smells of mental gymnastics.
I'm a huge fan of python (though I much prefer twisted to aio), but slower callbacks are unequivocally worse than faster ones, all other things being equal (which of course, they never are).
Anyway, slower or not, writing a small async service is still easier in Node.js. You can trust that no libraries block your event loop and I'm not sure there's quite anything like Express (simplicity+popularity) for async Python just yet.
I just did: those benchmarks show uvloop's performance, not python's, i.e.: they're designed to minimize time spent in callback code.
After 3.4, which was a stability release. The async stuff and the beginnings of optional typing went in at 3.5. Numbering probably should have gone from 3.4 to 4.0.
"I've been a gevent user for a long time and Python's decision to "bless" twisted by adopting it's patterns was a watershed moment for me, and basically was the beginning of the end of my belief that I'd ever adopt Python 3.
User jerf's comment that asyncio "more than [doubles] the complexity" is absolutely correct. Watch this video of Guido talking about tulip...or struggling to talk about tulip, rather. It's clear the dude is out of his depth and my god the recent changes to the language show that the inmates are now running the asylum... Seems like Python, in it's effort to chase the latest fads, is no longer the language I would endorse to someone new to programming. Whether you think that's a meaningful litmus test or not, the staggering amount of _crap_ that's infiltrated the language now completely flies in the face of the zen of python's statement that there should be one and preferably only one way of doing things. Fuck. I'm going to go code some lua now.
Even with its channels and scheduler, Go is still not as multicore as Erlang. And I say this as an avid Go user!
So, what's the issue you're facing?
I teach online advanced-Python programming workshops every month. The audience of each is 50-100 working developers from around the world, every one of whom use Python in their day-to-day work.
I start each class by polling who's using Python 2 vs. Python 3. A year ago, about 20% said they use Python 3, 80% Python 2. In the last 2 months, it's consistently 60%-70% Python 3.
Python's community has already plowed through the sigmoidal inflection point to 3; most just don't realize it. The linked article is years old.
"I teach online advanced-Python programming workshops every month... In the last 2 months, it's consistently 60%-70% Python 3."
So you're basing your conclusion on a sample of two? :)I teach advanced Python (and machine learning) courses too, albeit in corporate settings (groups of ~15, rather than 100), and it's still very much <20% for Python 3 there.
There's definitely going to be pockets of resistance. My attendees are a very wide-spectrum sample from many different companies and industries and even countries, so I have some faith in the trend that's showing up. Could be that there's some bias in my students for sure. Regardless, the ratio I've been seeing has been steadily increasing month after month since late last year.
Actually Py2's str class is a double-duty str/byte class such that some methods behave like str and others like byte.
py2>> len('¡no') #string len=3
#encoded UTF-8 byte array len=4
4 #always gives bytes.len not str.len
(see http://stackoverflow.com/questions/5471158/typeerror-str-doe...)Case in point: len("é") == 2, so even with unicode strings we don't have length as a character count.
As an english speaking person, I can clearly point at é and call it one character, but Python 2 or Python 3 doesn't agree. Rather, their str `len` doesn't agree with that, and that's fine. It's not a character count!
Though I don't know any "normal" character that requires composition ad-hoc that could serve as a better example.
That said, the grapheme cluster note will have examples of extended notions of characters that can't be represented by an equivalent single codepoint. There are some korean and indic examples and also emoji http://unicode.org/reports/tr29/
Oh and something that stirs the heart of us hackers: \r\n is a single grapheme!
visually_empty(s) is okay, len(s) is probably not.
[0]: When I say 'lists', I mean whatever the standard idea of a sequence of things is in the language. For C that's the array, or maybe the pointer+length pair. For Go it's a slice. For Rust, an iterator perhaps? For Python, it's a list.
How about these?
Do you want your programming-language stdlib String class to require a font metrics library?
(This isn't a rhetorical question; you can go either way. Objective C cares about grapheme clusters, and so needs to know about fonts.)
'fi' is two grapheme clusters even if the font renders it as a single glyph. 'é' is a single grapheme cluster even if the font renders it as two glyphs: 'e ́'
But it's the font that controls those semantics—because it's the font that knows what flags do or do not exist. For any pair of RIS codepoints that doesn't form a flag (in the opinion of a given font), they behave like two separate characters.
Thus: one grapheme cluster, or two, depending on the font.
And another example—this one much less "idiomatic", but not specifically decried by the Unicode committee: http://kudakurage.com/ligature_symbols/
That's a font, making entirely-arbitrary clusters out of codepoints. As far as I am aware, it's fully within its rights as a font to do so. There's nothing in the Unicode standard saying that the code-points ['f', 'i', 'l', 'e'], put in a row, can't combine to form a single grapheme cluster. They don't have combining behavior themselves, but—unlike, say, things in the Unicode "Separator" class—they don't have any property that says they don't combine with anything.
>Thus: one grapheme cluster, or two, depending on the font.
One glyph or two depending on the font. Two grapheme clusters, always.
>That's a font, making entirely-arbitrary clusters out of codepoints. As far as I am aware, it's fully within its rights as a font to do so. There's nothing in the Unicode standard saying that the code-points ['f', 'i', 'l', 'e'], put in a row, can't combine to form a single grapheme cluster. They don't have combining behavior themselves, but—unlike, say, things in the Unicode "Separator" class—they don't have any property that says they don't combine with anything.
No, I think those are glyphs. 'file' is always four grapheme clusters.
> a = bytes([97,98,99])
> print(a)
b'abc'
> a[0]
97
You can use regular expressions on a "bytes" object, as well as most of the string operations, such as ".center()" The "bytes" type in Python 3 still does double duty as an ASCII str/byte class.In this case print(a) calls a.__str__() which happens to default to calling a.__repr__() because a doesn't have an __str__ attribute.
a[0] is equivalent to a.__getitem__(0)
That's because the __repr__ of a bytes object instance formats the result into a human readable representation of the data which should ideally be identical to the syntax needed to create the instance, whereas the __getitem__ method returns a "real" and machine usable representation.
Try it...
>>> a
b'abc'
>>> a.__str__()
"b'abc'"
>>> a.__repr__()
"b'abc'"
>>> a.__getitem__(0)
97The vast majority of Python developers will only be writing and maintaining Python 2 code, because the vast majority of Python code is 2.x and will never migrate.
I mean, if the complaint is that it's too hard to make set of specific changes to a Python 2 program to make it a Python 3 program, how is it going to be easier to re-write in a new language when that's going to be a significantly more difficult project?
2. What is the material benefit to rewriting the whole thing from scratch in any language, just to get around an EOL timetable?
This is incorrect in at least two ways:
- Python 2.7.x str is _not_ ASCII! "\xff" is totally valid, but not a valid ASCII string.
- Python 2.7.x has bytearray.
No. 3.x is right, unless you have a darn good reason. Darn good reasons:
1. A library or legacy codebase is in 2.x, or a system will only support it, and it is impractical to refactor to 3.x
2. You are being paid to specifically write in 2.x. Often, this is because of reason 1.
It's pretty simple, really.
> Note: The urllib2 module has been split across several modules in Python 3 named urllib.request and urllib.error. The 2to3 tool will automatically adapt imports when converting your sources to Python 3.
The best-but-silly solution I found without introducing a dependency was:
try:
from urllib.request import urlopen, Request
except ImportError:
from urllib2 import urlopen, Request> from six.moves import urllib
>>> round(15.5)
16.0
>>> round(16.5)
16.0
I wonder what's the logic behind this.The rest is indeed opinion. The opinion of the python community after almost 10 (!) years after after the first release is quiet obvious: 3.x sucks!
I just don't know from where all the 3.x apologist appear as soon as there is a discussion. There always appears to be an inherent need to somehow defend this complete failure.
https://code.facebook.com/posts/1040181199381023/python-in-p...
Some of it you could do with 3rd party libraries and no syntactic support in 2.x, but it's absolutely false to say async has nothing to do with any 3.x features.
I'm also not sure how you got the impression that everyone thinks Python 3 sucks. The fact that you see "apologist" might mean something?
Performance isn't the only metric.
>The opinion of the python community after almost 10 (!) years after after the first release is quiet obvious: 3.x sucks!
It's certainly not obvious to me. I've been seeing and hearing great things from/about Py3...
>I just don't know from where all the 3.x apologist appear as soon as there is a discussion
Consider this mind-bender: many people are very, very happy with Py3.
You need to consider Cython, Celery, and C-extensions such as numpy for performance critical code.
Just because there are stragglers doesn't mean the community, as a whole, hasn't moved (or isn't moving).
(https://adtmag.com/articles/2016/05/24/microsoft-visual-basi...)
You're being disingenuous.
I've been dragged kicking and screaming into Python 3, (which I still hate), but I don't see any higher ground to swim too.
(As someone who has to deal with a lot of Unicode content, I consider Python 3 a blessing, but curious.)
but for me the real nightmare is all of the libraries. some have 2 and 3 support, some only 2, some with a 3 fork thats not maintained, etc etc.
every time i try to start a project using 3 i end up wasting a lot of time and going back to 2 anyways
Of course, diving into the newer version also adds a lot of debt, and possibly a total impasse, due to the lack of libraries that have made the update.
I guess it will be quite some time before it becomes foolish to still cling to py2
This gets mentioned in every hacknews thread on this subject, but I honestly don't believe I've seen any that weren't either already updated to support Python 3, or didn't have alternatives that worked just as well.
https://python3wos.appspot.com/ has a list of the largest packages in pypi, and there's very few that aren't available in Python3. httplib2 is easily replaced by requests. Supervisor isn't a library, it's an application. Same with carbon and graphite-web. Basically the only things on that list are the mozilla libraries, but IIRC some of those are in progress of being ported anyway.
Twisted is one of the few I can think of that still isn't there, but most of the core APIs are there, as well as a lot of secondary stuff - half a year ago, more than 90% of the unit tests were passing on python3.
Thanks for the resource.
Can I ask if you see any reason to not abandon Python 2 altogether when starting a new development project?
If not, and you need to deploy to RHEL/Cent 7, then maybe. They're still on 2.7, though software collections will let you install 3.x on either of them.
i've moved some forward, its not that hard. still seems like a mess
I'm also a sysadmin, and not a programmer. But I do a lot of my automation scripting in python, and have worked on a few larger projects in python, including one that's requirements meant it had to be Python2/3 compatible. I am not a fan of Python prior to 2.7 at all, and I think 2.7 is really just a bunch of bandaids trying to pull together a pretty crappy language, whereas 3.x is a joy to work with.
I talk about how a sysadmin perceives the state of Python, and a sysadmin usually works with stable OSes. And you know what? Most of the major distributions commonly used for servers use Python 2 as the default interpreter. The list of these distributions includes Red Hat/CentOS 7, Debian stable (Jessie) and soon-to-be-stable (Stretch), and Ubuntu 16.04 LTS.
> Plenty of modern distros ship Python 3 as the default Python, including Ubuntu. RHEL6 still uses Python2.6! It's horrid.
Erm... You compare "modern distros" with a release that is on its LTS? You know you're being unreasonable, right? Not to mention that Python 2.7 was released in 2010, the very same year as RHEL 6. It's hard to hold it against Red Hat having this in mind.
And how Ubuntu ships Python 3 as the default version? From what I see, in Ubuntu Zesty (17.04, i.e. the most recent release) package "python" has version 2.7.13-2.
> I am not a fan of Python prior to 2.7 at all,
Because...?
> [...] I think 2.7 is really just a bunch of bandaids trying to pull together a pretty crappy language,
Like...?
> [...] whereas 3.x is a joy to work with.
Becuase, in contrast to 2.x, it has the feature of...?
(the reason for this is to avoid breaking ancient scripts which naively assumed that "python" would always refer to Python 2, and allowing Python-3-aware scripts to be explicit about what version they were targeting)
The Ubuntu 16.04 Canonical provided AMIs on AWS don't even include Python 2, though it appears to be back in 16.10 and 17.04 from my double checking - but on 16.04, there is literally no python27 without installing it via apt.
RHEL and Cent have had Python 3 available in software collections since 6
And yes, since 6 is still not EOL the fact that they are still on 2.6 by default is something I can hold against them.
But per PEP standards, python should always be python2.x, and if it's not installed, not work at all. python3 should always be python3.
As for why I didn't like 2.6: 'io' performance was quite low, and much of what I've worked on makes heavy use of it. The C rewrite solves this. Lack of support in logging for logging over TCP. Being restricted to a single context manager when using with. Optparse instead of argparse. The lack of dictionary comprehensions (and I guess set comprehensions too, but I don't really use sets too frequently).
Why is Python 2.7 still not at Python 3 levels? I do a lot of work with international characters. That right there is enough, really. Outside of that? Just so much stupidity. Parts of the standard library with inconsistent names. Why are some libraries capitalized? Queue vs queue. Lack of asyncio.
Guess what? Freshly debootstrapped Debian doesn't have Python installed at all, too. And guess why? Because all the essential tooling in Debian is compiled. But then there is optional tooling, and Python 3 is yet to be used there.
But we were not talking about what interpreters are in a default installation. We were talking about Python 3 being the default Python.
> And yes, since 6 is still not EOL the fact that they are still on 2.6 by default is something I can hold against them.
No, you cannot. The primary thing RHEL provides is stability.
> Lack of support in logging for logging over TCP.
(1) Not like you cannot add it trivially. (2) It's not a good idea to work in Python's logging with unreliable things like network. You should always isolate Python logging from those things by using spooler. BTDTGTS.
> The lack of dictionary comprehensions (and I guess set comprehensions too, but I don't really use sets too frequently).
Of course, because those are essential part that cannot be trivially emulated by dict() constructor.
From all you said, only I/O performance, context managers, and lack of argparse are somewhat sensible arguments. They sum up to too little for me to consider them a significant difference in how it feels to write code (not to mention that optparse is adequate and I don't see argparse as much of a progress), but then I normally use half a dozen of other languages and runtimes, so I have a different perspective.
A few quick examples:
Base64 encoding returns bytes. Why would anybody _ever_ want that? The whole purpose of B64 encoding is to make something string-safe.
It's also now invalid to have this as a project structure: Name/name.py (with a Name class) in it.
Which I would say is literally the most sensible common project structure to have. Now you have to call the file with the name class 'core' or 'main' or anything besides the actual description of what it is. Of course, you'll get no help from the errors if you hit this problem.
"Dictionary view objects" are horribly unsemantic and annoying to teach. How is the language improved by having this no longer work `k = d.keys(); k.sort()`? Just give me a list.
I'm maintaining a fairly large and popular Python 2/3 project and all of the errors are coming from the Python 3 side, and the maintainability of the project has been decimated by needing to support both versions.
They should have just made a 2.8 with asyncio and unicode strings.
My hope is that somebody will make a new language that does to Python what Python did to C/Java. For day-to-day scripting, let's get really serious about programmer ergonomics, semantics and maintainability above all.
Ex, why not let me do something like this out of the box:
get https://api.github.com/users/Miserlou as miserlou
print "My name is " miserlou.name
Transparent/automatic web requests, content-type checking, serialization parsing, string formatting, network reference parsing, etc. Let the user be more specific if they need to, but design heavily around the most common use case.Still, it seems that this is not thought through properly. What should the language do if the server does not return JSON? And can't we basically do this in Python already?
a) Speak flutent HTTP b) Understand Content-Type c) Deserialize to a common format
all completely transparently. If the server returned XML or MsgPack, it wouldn't matter, the code would work the same.
Ideally, we could imagine this going a step further, and having the language speak REST entirely.
Python's requests is a nice prototype, ergonomically speaking, but we can go much further.
import <json>
import <xml>
load-*: function [site] [
p: open site
content: read p
http: query p
close p
parse http/headers/Content-Type [
"application/json" return (load-json content)
| "application/xml" return (load-xml content)
] else [
fail "Content-Type not recognised"
]
]
miserlou: load-* https://api.github.com/users/Miserlou
print ["My name is" miserlou/name]You'll need the Ren/C branch of Rebol 3 for this:
* repo - https://github.com/metaeducation/ren-c
* pre-built binaries - http://metaeducation.s3.amazonaws.com/index.html
So, if for example, Github did return XML and it looked something like this (shown in Rebol console):
>> x: load-xml {<root><name>Mr Miserlou</name><login>xxx</login></root>}
== [
<root> [
<name> "Mr Miserlou"
<login> "xxx"
]
]
So to get top-level tags it's just: >> second x
== [
<name> "Mr Miserlou"
<login> "xxx"
]
Now load-json also has a flat option so that a good way to unify things. Here's an updated example showing this: import <json>
import <xml>
load-*: function [site] [
p: open site
content: read p
http: query p
close p
data: parse http/headers/Content-Type [
"application/json" return (load-json/flat content)
| "application/xml" return (second load-xml content)
] else [
fail "Content-Type not recognised"
]
;; next 2 lines just turns it into a hashmap so can do: miserlou/name
;; without it could have done: miserlou/<name>
;;
for-skip data 2 [data/1: to-word to-string data/1]
make map! lock data
]
miserlou: load-* https://api.github.com/users/Miserlou
print miserlou/nameStill neat though. Sometimes I wonder if I should learn REBOL (or Red?) or something.
Here's an example using latest build of Rebol 3 (Ren/C branch)...
import <json>
miserlou: load-json read https://api.github.com/users/Miserlou
print ["My name is" miserlou/name]What corner case do you think python 3 is solving with the return type being a byte array? Surely you must have looked into it because clearly it isn't arbitrary ... Right?
>The whole purpose of B64 encoding is to make something string-safe
Guess again.
"Base64 is a group of similar binary-to-text encoding schemes that represent binary data in an ASCII string format by translating it into a radix-64 representation."
Binary. To. Text. As in - bytes in, text out. Come on now.
Python3 errs on the side of not converting bytes to strings or vice versa unless its an explicit conversion on the bytes/string object itself. And it is fan-fucking-tastic!
Here you go, a sorted list of dict keys:
k = sorted(d.keys())In Python 3, I have to tell my students that
breakfast = ["bacon", "eggs"]
sorted_breakfast = breakfast.sort()
works, but breakfast = {"bacon": 2, "eggs": 3}
sorted_breakfast = breakfast.keys().sort()
doesn't. They will ask, "why?", and I have to say "just because."Instead, you have to use "sorted", even though "sorted" isn't even a verb, it is a property. "Why is sorted() rather than sort()" - "just because."
Similarly, "where is there a b'' in front of my name", why can't it find my module, and on and on and on.
The advantages of Python of a teaching languages are mostly gone now, and I would probably use JavaScript to teach beginners now, whereas I previously would have used Python2.7.
> breakfast = ["bacon", "eggs"]
> sorted_breakfast = breakfast.sort()
> works
Well, some of your students might point out to you that your `sorted_breakfast` is `None`, because that is what `sort()` returns, and even this example doesn't work as you have wanted ;)
On the other hand, if you have used `sorted(breakfast)` (and `sorted(breakfast.keys())` in other example), both examples would work as intended, and you couldn't blame Python 3.
> "Why is sorted() rather than sort()" - "just because."
It is not "just because", it is because it returns a sorted list (which is exactly what you wanted), compared to returning None.
Also because `sorted()` works on any iterable, whereas .sort only works on lists.
The python.org tutorial and FAQ have answers to these questions.
I think it's unethical to tell a student, "just because" instead of, "I don't know why."
Returning an iterator instead of a list has the advantage of not having to create a new object in case that is not needed, for example if you are going to filter a big dictionary just to obtain a few items then copying the keys of the dictionary and then filtering is not a good way of using memory efficiently.
How do you even get them there? I mean, input() returns Unicode strings. So do all operations on text streams.
In [2]: sorted(breakfast)
Out[2]: ['bacon', 'eggs']
Done. One and only one obvious way to return a sorted list of keys of a dict.
No, it's to make something ascii-safe which is a completely different concern.
> It's also now invalid to have this as a project structure: Name/name.py (with a Name class) in it.
What?
> mkdir Name
> echo "class Name: pass" > Name/name.py
> python3 -c "from Name.name import Name;print(Name)"
<class 'Name.name.Name'>
> "Dictionary view objects" are horribly unsemanticUnsemantic? They're just the opposite. keyviews and itemviews are now sets, which is semantically sensible and really useful to get the intersection of two dictionary keysets, the only missing part is being able to subdict based on a keyset.
> Just give me a list.
list(d.keys())
Why are you even using .sort()> unicode strings.
That's what broke compatibility FFS, that's the entire reason why the maintainers felt they could change the rest of the language.
Especially for numpy/matplotlib scientific stuff, I'd imagine Go would not be a suitable replacement (but maybe Julia would be).
I also like Go and all the Python replacements. Definitely cheering on the exodus from Python3. The alternatives are all good stuff. I don't believe in 'one true god', and that god is definitely no longer Python. Py3 is a bloated mess of feature soup with no performance enhancements, they got so much wrong with it and is a case study in how to mismanage a language migration.
I'd probably been onboard if they would've done a little better job. It seems the migration was for GvR and the rogue band of core devs (easier to maintain, their little pet project features) rather than the userbase that made Python what it is. They just did what was easiest for them and are pretty arrogant about it, saying they do the work so they decide. Ok, I'll use something else then with that attitude. The arguments for it are beyond silly and horribly uninformed, like "added support for unicode" is repeated ad nauseum.. I was using unicode with Python since 2.6. I can't tell if people really are that uninformed or lying to promote Python3. It was just already too big to do what they did and how they did it.
But I'm not going to debate that with anyone, happily using TypeScript now and never looking back. It runs faster on V8 than Python ever will and I'm able to do almost everything you could do in plain JS with it. Which is a significant array of tasks. Otherwise, while I reach for TS first all the time now, thinking about getting into Rust for its C ABI and performance for a reusable library idea that I have. TS/Rust is a potent combo and covers an astonishing amount of ground (and does it well). Both of them are very practical.
I get the argument if a programmer doesn't like dynamic languages in general, but not because one dynamic language has become too flexible.
Python even has limited generics now through mypy and pep 484.
You can use the gccgo runtime from Nim and get your goroutines and channels working with generics, macros and everything else Nim has to offer: https://github.com/stefantalpalaru/golib-nim