
Key differences between Python 2.7.x and Python 3.x (2014) - Tomte
http://sebastianraschka.com/Articles/2014_python_2_3_key_diff.html
======
mnm1
"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?

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

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

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

Um, yes it does:
[https://cloud.google.com/python/quickstarts](https://cloud.google.com/python/quickstarts)

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

------
elnygren
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/](https://magic.io/blog/uvloop-blazing-fast-python-networking/)

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

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

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

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

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

~~~
Radim

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

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

------
riazrizvi
> 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...](http://stackoverflow.com/questions/5471158/typeerror-str-does-not-
support-the-buffer-interface/34688434#34688434))

~~~
kzrdude
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("é") == 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 é 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!

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

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

~~~
kzrdude
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/](http://unicode.org/reports/tr29/)

Oh and something that stirs the heart of us hackers: \r\n is a single
grapheme!

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

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

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

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

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

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

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

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

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

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

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

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

------
minimaxir
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](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

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

> from six.moves import urllib

------
nnd

      >>> round(15.5)
      16.0
      >>> round(16.5)
      16.0
    

I wonder what's the logic behind this.

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

------
murtnowski
Why is this still a thing?

~~~
thomastjeffery
Libraries and pypy.

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

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

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

~~~
int_19h
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...](https://adtmag.com/articles/2016/05/24/microsoft-visual-basic.aspx))

------
Double_a_92
The print command needs brackets. :^)

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

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

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

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

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

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

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

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

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

~~~
draegtun
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]

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

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

You'll need the Ren/C branch of Rebol 3 for this:

* repo - [https://github.com/metaeducation/ren-c](https://github.com/metaeducation/ren-c)

* pre-built binaries - [http://metaeducation.s3.amazonaws.com/index.html](http://metaeducation.s3.amazonaws.com/index.html)

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

~~~
draegtun
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

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

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

