Hacker News new | past | comments | ask | show | jobs | submit login
Key differences between Python 2.7.x and Python 3.x (2014) (sebastianraschka.com)
212 points by Tomte on May 7, 2017 | hide | past | favorite | 168 comments



"I would say there is currently no “right” or “wrong” as long as both Python 2.7.x and Python 3.x support the libraries that you are planning to use."

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?


The way forward is to use Python 3. That's been the way forward since it was announced that 2.7 would be the last version, and that everything after it would just be bugfixes. The way forward became even more clearly defined when the date was set for even those to stop.

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?


> 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.

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.


> Google App Engine still doesn't support Python 3.

Um, yes it does: https://cloud.google.com/python/quickstarts


You're both half-right: the "standard" App Engine environment is "Python 2.7 only", via the link you just gave. The newer, flexible env (with less bullt-ins) does 3.x too.


Right, because Google likely has a tremendous codebase which would prove difficult and costly to port. If they were making a decision today and had no existing python systems, do you think they'd choose the version that's going to be EOL in less than three years?


I've been listening to Python podcasts recently and this is certainly the impression I'm getting. Plus, there are always backports for those who cling to 2.7.


What podcasts are you listening to?


The link appears to be a few years old now, so its advice here I think is a bit out of date. And some might argue it would have been out of date in 2014 as well.

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.


The last two things I have on Python 2 are:

- 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.


Why does the code that "has to run on HostGator shared hosting" has to live there specifically, if you can say? It should be a simple project to move that code somewhere else.


I've never heard of Robot OS, looks interesting! Yea, unfortunately its the niche stuff like that which experience the most problems (or at least I assume its fairly niche - I do nothing with robotics).

In those cases, one can, without too much effort, write forward-compatible python 2 code at least.


Interestingly, most of ROS (core) is py3 compatible. Its only a lot of the libs that aren't. Unfortunately, that includes some very common libs.


Here's the advice I usually give:

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.


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?

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?


I agree. I'm sure it's much easier for Python 3 core language development to happen versus 2, but for a regular joe what carrots are there, or is it really all sticks?


For system-related stuff, python 2 is already 'everywhere', as it's used all over the place for that kind of thing. Even some nodejs modules depend on python for their installation. But if you're going to be doing more than making a standalone script, python 3 should be your target: that's where the maintenance is going to live, and that is where any 'cool_new_module' gets targeted. If you're going to make something big, do it in an area that gets support.

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.


Check out the "what's new" documents for the various Py3k versions. v3.6 had very nice additions.


There's no reason those enhancements couldn't be part of 2 other than the maintainers decided to abandon the language for their own maintabity. That's their peragotive, but doesn't provide material benefits to the actual users.


The maintainers implemented enhancements in both 3.x and 2.x for many years. Eventually they got tired of it. Version 2.7 corresponds to 3.4. The reason why 3.5 is the first 3.x that started to gain a following was that Guido announced there'd be no 2.8.

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.


> 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?

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.


> how can you ask someone who is new to the language to just choose

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...


There is a clear path forward. It's Python 3. The Python community unanimously agrees that the way forward is Python 3. Many libraries are planning to drop support before 2020, many have already dropped support, and the rest never supported Python 2 in the first place.

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.


Python3 is a totally different beast nowadays from Python2.

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.


IMHO: after 3.5, we are clearly in the next iteration of the language.

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.


Python 3.5 is compatible with Python 3.4. Python 4.0 would be a silly number to use, it implies that there's incompatibility.


I can't find a source at the moment, but I'm pretty sure that Guido said that python 4.0 would just be the version number that comes after python 3.9. There is no intention of having another break in backwards compatibility, like there was between python 2 and 3.


He's said 3.10 more recently than that:

https://twitter.com/gvanrossum/status/583346987925278720


Is it just me, or comparing Python's async/await to Go is misleading. As far as I know, even with async/await, Python is still not multicore.


Async IO is solving a different problem than you're complaining about. Python is effectively multicore in nearly every use case. The only trouble is there's no free lunch -- the multicore solution depends on which problem you're facing.

So, what's the issue you're facing?


even with async/await, Python is still not multicore.

Even with its channels and scheduler, Go is still not as multicore as Erlang. And I say this as an avid Go user!


What does something not being as multicore as something else mean?


Multicore in the sense that the underlying runtime (for the lack of a better word) scales to multiple cores. Like two threads in python cannot run in parallel (like at the same time, not like second one gets scheduled if first one waits for IO or network), the way a goroutine in Golang does.


It would be great if the GC was also multicore. As it is, the task of splitting up your application into multiple processes to have more GC still involves too much friction.


>is actually faster than Node.js

Uhhh I call BS until proven otherwise. Maybe the event loop is faster, but I'm willing to bet the callback code is slower.


> 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.


The "proof" (benchmarks, yeah, I know) is in the provided link. Feel free to shoot them down.

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.


>The "proof" (benchmarks, yeah, I know) is in the provided link. Feel free to shoot them down.

I just did: those benchmarks show uvloop's performance, not python's, i.e.: they're designed to minimize time spent in callback code.


the callback code being slower is actually a feature in my opinion.. http://stackoverflow.com/questions/18542484/why-callbacks-ar...


I'm struggling to see where in the wall of text this notion is supported.

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).


Depends on many things. What task are you trying to accomplish?


In any non-contrived example, CPython's callback code will be slower than equivalent JIT-ed code from v8.

Please don't play the "it depends" card just to be smug. It lowers the level of discourse.


I ain't being smug. If I were, I might use fancy words like "discourse". But we're not playing cards here, are we?

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.


The Python async story appears to be a bit of a mess though. There was some discussion recently on this here: https://news.ycombinator.com/item?id=14240125 .


And this discussion less recently: https://news.ycombinator.com/item?id=12829759 "I don't understand Python 3 asyncio". Along with the comment somewhere in that thread by coleifer:

"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.

https://www.youtube.com/watch?v=1coLC-MUCJc "


They have managed to take the async/await pattern and make it as much fun as Perl POE.


We did this in python 2 with greenlet. It's cool that people can do it today by writing "async" in a thousand different places though!


I haven't written Python in a few years, and recently when I needed to read some Python code thinking it would be familiar, I am completely unprepared to see async/await peppered everywhere. It is indeed a big change.


To people whining "why hasn't Python's community moved to 3 yet": It has.

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.


Poorly worded. I taught 4 classes in March and 4 in April, over 500 unique engineers total (some were in more than 1 class).

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.


> Python 2 has ASCII str() types, separate unicode(), but no byte type.

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...)


Python 3's "bytes" type can't quite decide whether it's an array of small integers or a string.

    > 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.


Python 3:

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)
  97


No need to get too much into the meaning of the length of a str. It's neat to know the definition but neither choice gives you a good “string length” for real text.

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!


"Character count" (i.e. grapheme cluster count) only exists once you apply a font—because of ligature rules and some other stuff.

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.)


I disagree. A grapheme cluster and a glyph are different things. The former is not dependent on the font.

'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 ́'


Consider the https://en.wikipedia.org/wiki/Regional_Indicator_Symbol s. In every way that matters, these "act as" one 'character': you can't set your cursor position to be between them; backspacing one should delete both; the flag takes up one terminal col (even if it is rendered as two) such that "\033[1Dx" (cursor-left 1, print "x") will overwrite the whole flag, etc.

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.


Cursor position is based on glyphs though, not grapheme clusters. Grapheme clusters are a well-specific Unicode concept.

>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.


That one is maybe not the best example, since len(unicodedata.normalize('NFC', "é")) == 1

Though I don't know any "normal" character that requires composition ad-hoc that could serve as a better example.


I think it's a fine example since the decomposed version clearly exists and can arrive as data into your program in a number of ways.

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!


This (different forms and no automatic normalization) is a "feature" of Unicode. It would be wrong of Python to try to cover it up.


Yes, so it's wrong for anyone to pretend len() or even indexing of a str is about characters, it's about codepoints of the string.


IMO, len("") should raise OperationHasNoCommonSenseTodayException, just to not confuse unicode newbies. Modern text is not an array, it is a format, a complex format. Zero-width, double-width monotypes, combining, direction marks, normalization, etc. Almost no one wants to know about codepoint details when working with "just input strings", and those who want may use special namespaces for that. There is no point in making len() an alias for unicode.volatile_number_of_distinct_code_points().

visually_empty(s) is okay, len(s) is probably not.


They're all valid measurements. The length of a string could be measured in bytes (which doesn't require you to know the encoding), code points (which doesn't require huge Unicode grapheme clustering tables), grapheme clusters (which doesn't require a font) or even pixels (which does require a font).


The best thing a language (or library) can do is to not bless any single one of these as the default. Strings shouldn't have a length at all. They should provide properties/methods/accessors like byte_count, codepoint_count, grapheme_count etc. Make the user of the API think every time they're asking for a length of the string - which one do they actually need? Which one is the best for whatever they're trying to do?


Can you name a single language that does that? I can't think of one.


None of the mainstream ones that I can think of. Which is really unfortunate, not the least because the defaults are all over the place - usually it's either bytes (when strings are UTF-8) or code units (when strings are UTF-16 - note, code units, not code points, so surrogate pairs count as 2!). Occasionally it's genuine code points, as in Python. Which, I think, goes to show why it's such a mess.


I think that if you treat strings as just lists[0] of UTF-8 code units, and code points, grapheme clusters, etc. are just views/adapters of those bytes, you're probably going to benefit the most.

[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?


The likelihood of the current 2.x codebase being ported to 3.x is lower than new code being written in a new language. It will be ported to a new language, such as Golang.

The 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.


How on Earth does it make more sense to re-write an entire working program in an entirely new language than it does to simply update from Python 2.7 to Python 3?

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?


Because no sane person wants to do the investment unless is provided material benefits. 2->3 provides no such material benefits, which is why they're being so aggressive about EOL timetables.


1. 10 years is not aggressive for an EOL timetable.

2. What is the material benefit to rewriting the whole thing from scratch in any language, just to get around an EOL timetable?


> Python 2 has ASCII str() types, separate unicode(), but no byte type.

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.


> I would say there is currently no “right” or “wrong” as long as both Python 2.7.x and Python 3.x support the libraries that you are planning to use.

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.


Hit an interesting issue when trying to make my urllib2 Python code behave the same way under both Python 2.7 and 3.6, which is fortunately documented: https://docs.python.org/2/library/urllib2.html

> 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


Use six for this. They provide stable import paths for stdlib modules that have moved.

> from six.moves import urllib


  >>> round(15.5)
  16.0
  >>> round(16.5)
  16.0
I wonder what's the logic behind this.


Minimizing accumulated error. The term you are looking for is "banker's rounding"



Why is this still a thing?


Libraries and pypy.


Why hasn't the Python community moved on to Python 3 yet?


Who says it hasn't?

Just because there are stragglers doesn't mean the community, as a whole, hasn't moved (or isn't moving).


The fact that even nowadays people are still wondering about python 2 vs. 3 shows that the community hasn't move to python 3. Otherwise this wouldn't be even a question.


There are still people who haven't moved from VB6 to VB.NET. It's the nature of such major, breaking transitions.

(https://adtmag.com/articles/2016/05/24/microsoft-visual-basi...)


No, it shows that those people are on the fence. It says nothing of the community on the whole.

You're being disingenuous.


Uninformed people.


Most of it has, and it is good to document upgrade pathways for 2 to 3 migrations. Some of those migrations require 2 and 3 compatible code. I also highly recommend using the six library.


I'm using Django 1.8 first with Python 2.7 then migrated the code to 3.4 with no problems


You can migrate to Django 1.11, it's also LTS like 1.8.


Google has been a big holdout within the community, and by continually releasing Python-based machine learning software without Python 3 support, they've helped slow its adoption in that field. Otherwise, most of the community has moved to Python 3.


I'm curious, which libraries are you talking about specifically?


Because it is a serious regression.


That's an opinion, not a fact.


Performance can be measured.

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.


Performance can be measured. And what better way than at scale. Facebook wrote an article a while back about how all new code is written in python3, and they are seeing huge performance wins because of it.

https://code.facebook.com/posts/1040181199381023/python-in-p...


Most of the performance gains seem to come from the async/await stuff which is a rather late development which has actually nothing to do with any 3.x features. Could be done with 2.x as well.


Async/await is a 3.5+ language feature, and Python's core integration of async support, both at a language level and in the standard library, is all 3.x stuff.

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.


>Performance can be measured.

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.


Let's just say that Python 3 is, in fact, slower than Python 2. Performance is only part of what makes a language great. In fact, if you need raw performance, Python is not the language to go. Most of my performance intensive code run with NumPy or Pandas, which is not Python anyway and are not at all affected.

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?


Funny, I was just wondering where all of these 2.x fans who think that porting to 3 is harder than re-writing everything in Go show up from as soon as there's a discussion. There always appears to be an inherent need to somehow describe choices that make sense for the majority of the community as a complete failure, when they're really working out just fine.


Single threaded single process Python 3 is faster than Python 2 on I/O intensive workloads if you use asyncio effectively.

You need to consider Cython, Celery, and C-extensions such as numpy for performance critical code.


The print command needs brackets. :^)


This has ruined Python for me. Gone on far too long and Python3 ended up being technical churn anyway rather than technical innovation. Not worth the break. I ended up replacing Python.


While an unpopular opinion, I believe Python has lost its way too. "There should be one-- and preferably only one --obvious way to do it." - yeah I don't see it and that used to be one of the reasons I loved Python. They used to at least try for that to hold true, not it's like they try for the opposite. I much prefer Go these days.


I understand preferring Go for static typing or performance, but not because a dynamic language gives you more than one way to do things. If don't like that Python has gained too many features, why not use something like Lua? Why jump into a more restricted language that's going to require you to write more code?

I get the argument if a programmer doesn't like dynamic languages in general, but not because one dynamic language has become too flexible.


I looked at Lua briefly instead of Go, but it looks like the concurrency story is lacking. Go also has an enormous standard library which helps for quick tasks.


Go will probably be a mess in 20 years as well.


Yet still no generics.

Python even has limited generics now through mypy and pep 484.


> Yet still no generics.

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


But where did you go?

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.


TypeScript, and I'm absolutely loving it. So much of what I do is JS and this lets me do modern JS with many libraries and I get type safety. The only thing I can't accomplish with it, from local apps to webapps to mobile apps. I haven't used a better choice for goto language than TS. I completely understand your feeling though, I was in the same boat for a couple years till I tried TS.

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.


Curious, what do you hate about Python 3, or is it just hating the migration process?

(As someone who has to deal with a lot of Unicode content, I consider Python 3 a blessing, but curious.)


I have a whole blog post/rant brewing about that topic, but on the whole, I just think it feels like it was designed by committee rather than a visionary. They've abandoned the common usage case in favor of the corner case. It also makes it much harder to teach.

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.


> Base64 encoding returns bytes. Why would anybody _ever_ want that? The whole purpose of B64 encoding is to make something string-safe.

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 unsemantic

Unsemantic? 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.


There are other scripting languages that have good support and strong communities. There doesn't need to be yet another programming language. Use Ruby, JS or PHP 7 instead. If it's scientific computing, Julia fills the niche very nicely. Or R.


My point is that we should go a level "higher" than any current offering.

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.


This is the kind of stuff Rebol wanted to do, although i don't know if it covered this particular case.


Yep, the moment I saw that I though "REBOL"! (Actually, I thought of Red, but same idea.)

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?


It's a trivial example, but the point would be that the stdlib would have the ability to

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.


There is nothing currently built into Rebol stdlib that replicates exactly this. But here's an example of how it could be done...

    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]


Is this hypothetical, or does the stdlib actually have load-json and load-xml?


Above works, the <json> & <xml> imports are pulled off this remotely hosted common library - https://github.com/r3n/renclib

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


Okay, as someone who doesn't know REBOL, what is the effect of miserlou/name if the server returns XML? The string value of a top-level <name> tag?


Ah this was a different XML module than I was thinking of because this is complete DOM parser!! But even so it does produce (by default) a flat representation of the XML.

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/name


Okay, that's quite good! I'm going to see how good this can get with the Python std lib later. Probably not quite this nice.


Actually, I think I was wrong. You can get something this nice in Python. It just requires a bit more glue code in the case of JSON, and a lot more glue code in the case of XML. All told, I figure Python might 10x more code than REBOL here. I'm not sure if it's fair to hold this against Python though. It's "just" a question of libraries. And it's only fair to hold libraries against a language if the library itself would be hard to write. Which in this case I think it wouldn't.

Still neat though. Sometimes I wonder if I should learn REBOL (or Red?) or something.


Um, what if the server returned, say, a JPEG? Or a plain old HTML webpage, complete with inline CSS and script tags?


Very close!

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]


I like that! Are you sure there isn't some language that does this already?


> `k = d.keys(); k.sort()`? Just give me a list

Here you go, a sorted list of dict keys:

    k = sorted(d.keys())


You've completely missed the point. I'm not saying it can't be done, I'm saying that the new way is stupid.

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.


> In Python 3, I have to tell my students that

> 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.


> 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.


I know that the best way to learn is "see one, do one, teach one" but I wish you'd put more effort into learning the language before teaching it.

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."


You're replying to the wrong person. I'm not the one who is doing teaching, I'm just the guy who corrects the teacher who hates Python 3 (for wrong reasons) ;)


Sorry about that.


FYI... neither of those work. Sort (using the dot sort() notation) operates on a mutable list in place, and returns no value. Never use it on the right side of an assignment. Its like dict's `update` in that regard.


your example sorted_breakfast doesn't work, in python 3.5 sorted_breakfast == None. Sort is a verb that modifies the receiving object, sorted is for returning a new object that is a sorted copy of the original, so you need to allocate two times the object.

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.


> Similarly, "where is there a b'' in front of my name"

How do you even get them there? I mean, input() returns Unicode strings. So do all operations on text streams.


In [1]: breakfast = {"bacon": 2, "eggs": 3}

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.


>Base64 encoding returns bytes. Why would anybody _ever_ want that?

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.


From Wikipedia:

"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.


Its intentional, in part because of all the mayhem caused by Python2's "free-spirited" view on whether a thing is bytes or text. And that "free-spirited" view caused A LOT of mayhem.

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!


How do you feel about this:

https://github.com/naftaliharris/tauthon


i dont do a lot of python, and i think 3 is an improvement

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


Personally, I haven't found any must-have libraries for Python 2 only that don't have a satisfactory Python 3 alternative.


This is my major confusion as well. It seems not worth it to begin work in an older version because debt is inherent right at the start, and updating code (for a new language version) is a personal peeve (or irritant). It's irrational, so don't ask, but I avoid it everywhere I can.

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


What libraries are unavailable in Python 3?

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.


I can't offer you any kind of solid case. My Python experience is admittedly limited. I've been working to get more into it lately.

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 you control the deployment environment, none that I can think of.

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.


Oh thanks for the tip. I work with CentOS regularly, but haven't worked on a Python project in that environment yet.


idk, two sound libraries, an image processing library.

i've moved some forward, its not that hard. still seems like a mess


I, being a sysadmin, still consider Python 3 this new, shiny thing that is yet to become widely used. Linux distributions still use Python 2 code for their infrastructure, so Python 3 is something big I would need to specifically order to install that would give me negligible gains.


The Red Hat family of distros being decades behind isn't really an indication that things they aren't using are new and shiny. Plenty of modern distros ship Python 3 as the default Python, including Ubuntu. RHEL6 still uses Python2.6! It's horrid.

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.


> The Red Hat family of distros being decades behind isn't really an indication that things they aren't using are new and shiny.

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...?


You do need to be careful when arguing about names: the official upstream advice from the Python core team is that, for example, invoking "python" (just "python") should always execute Python 2 (or report "command not found" if no Python 2 is available). Invoking Python 3 should always be "python3".

(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)


Debian has included Python 3 since Squeeze.

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.


> The Ubuntu 16.04 Canonical provided AMIs on AWS don't even include Python 2, [...] there is literally no python27 without installing it via apt.

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.


Python is Ubuntu's preferred language for system tools, and these now run under Python 3. Both Debian and Ubuntu have policies of using Python 3 wherever possible. The "python" command still invokes Python 2 to make sysadmins' lives easier.[1]

[1] https://www.python.org/dev/peps/pep-0394/


>> [...] whereas 3.x is a joy to work with. >Becuase, in contrast to 2.x, it has the feature of...? Unicode strings makes my life a lot easier when dealing with anything international. Pretty much every difference made was better for the language.


Nobody expects sysadmins to use shiny new things. When you guys use something new, its because its actually already probably old - at the very least, its no longer shiny, and possibly even moldy. And even then you grumble about it. =)


+1.. exactly my experience with sysadmins.. install all of the just developed software of the devs on a 4+ yeah old rhel 6.5 (with custom packages for everything of course) so it's stable and tested and we can haz red hat support which we never use.


I've very happily replaced Python with Go (backend online services, misc command line tools).


And that's a good fit for Go, but Python is used for lots of other things.


Oh for sure, which is why I specified.

Especially for numpy/matplotlib scientific stuff, I'd imagine Go would not be a suitable replacement (but maybe Julia would be).




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: