
Python 3 makes it easier to develop high-quality software - ColinWright
http://migrateup.com/main-difference-python-3/
======
pornel
This is sad and frustrating. The article is trying to convince people to
upgrade _to_ a 7-year-old version of Python! And everyone is still skeptical
about it, thinking it's too new, too risky, unproven, and libraries aren't
ready _yet_.

Python 3 adoption takes longer than entire NodeJS lifetime. In the same
timeframe PHP introduced _and_ EOLed 5.3 (edit: and there were 4 years between
release of 5.0 and EOL of 4.x, which involved backwards-incompatible
refactoring of OO semantics).

~~~
rdtsc
> And everyone is still skeptical about it,

They are not skeptical. Nobody thinks "yeah if I just wait long enough, Python
3 will go away and 2.8 will come out".

They just don't see an incentive to update. Simple as that. It is basic
economics of time and money.

Python 2 wasn't terrible and Python 3 isn't dramatically better. Unicode and
other stuff in Python 3 is nice. Is it nice enough to start digging into
stable, working, money making code just to say "Yay, Python 3"? I think the
development community has spoken by how it was handled. It's gonna happen but
it will happen at a very slow pace.

Imagine this alternative scenario -- "Python 3 brings 3x speed improvement +
removed GIL". Ok, I bet you, there would have been a much faster adoption
because now there is a greater incentive to justify it. People would think
"Yeah, I'll destabilize my code a bit but I gain performance, I can do that".

Someone in a sibling comment suggested "They should have just stopped updating
security patches for 2.7, that would have forced them to use 3.0". That's ok
if Python holds a monopoly on development languages. But it doesn't. As soon
as that happens developers will not just look at updating to Python 3, they'll
start looking at other ecosystems: Go, Elixir, Java, Clojure, Scala, NodeJS
etc.

~~~
mangeletti
I could not agree more.

To add to this; if it included even a 2x speed up / memory reduction, I think
90% of everyone would have switched by now, and you know what else? Go
probably wouldn't exist.

~~~
thrownaway2424
This is a good point. Go is a direct response to Google's experience with
Python.

------
falcolas
I've said it before, I'll say it again. When all of the major Linux platforms
provide the same pre-built Python 3 packages for the packages I use, I'll make
the migration. Until then, it's just easier to stay on Python 2.

Yes, I could build the packages/wheels myself. Yes, I could install a compiler
on the target machine and let the binaries build from scratch. I won't,
however, since it's a lot of time for remarkably little benefit. Python 2 is
still well supported, and is a great language to program in.

Yes, Python 3 has cleaned up some of the rough edges of Python 2; but the
improvements are still not significant enough to offset the cost of porting
libraries and building packages.

~~~
maweki
but for node we expect everyone to install/build from source an not use the
supplied packages because they are ancient, in comparison.

Which distribution doesn't ship python3.3?

~~~
falcolas
Most ship python 3.3, but most of the libraries which the distro provides pre-
compiled are not Python 3.

e.g.

python-mysql python-django python-keyczar python-pyhsm

> but for node we expect everyone to install/build from source an not use the
> supplied packages

This is not necessarily an improvement in the state of packaging. Verifying
that unsigned source code has not been changed is a hard problem (which NPM
has not yet solved). Installing compilation tools and extensive header files
on a production machine opens up a new class of security vulnerabilities on
that machine (whether a VM, container, or bare metal).

~~~
eeZi
There's Anaconda too: [https://www.continuum.io/why-
anaconda](https://www.continuum.io/why-anaconda)

Many companies use it to run a recent Python stack on any Linux distro they
like.

~~~
meej
Anaconda was the easiest way for me to get Python 3 running on my Slackware
instance. I am very pleased with it.

------
stevecalifornia
When I went to learn Python I was immediately faced with a choice that would
have profound effects on my future success: Python 2 or Python 3.

Both sides are extremely persuasive and thus I felt that _no matter what
choice I made it was the wrong one_ and would haunt me down the line.

So I just stuck with a different modern language that has wide acceptance and
isn't battling with itself.

~~~
adrianlmm
The same thing hapenned to me in 2011, so I ended learning Ruby, no regrets.

~~~
takeda
Which is quite ironic, because (at least from my experience) Ruby constantly
breaks backward compatibility.

~~~
jrumbut
It's not necessarily about breaking or maintaining backward compatibility that
matters here. It's about how supporting two similar looking yet ultimately
incompatible versions creates confusion for new users, driving them away.

This is the same issue facing Perl (although the Perl situation seems more
dire) WRT Perl 5 vs Perl 6. For Python maybe the benefits of keeping Python 2
alive for large users offsets the harm of any confusion, I have small projects
(all in Python 3) so it's a rare annoyance rather than a deal breaker.

~~~
labster
> This is the same issue facing Perl (although the Perl situation seems more
> dire) WRT Perl 5 vs Perl 6.

The situation with Perl is neither more dire nor really the same issue as with
Python. Perl 5 is not going away. Perl 6 maintainers are not the same people
as Perl 5 Porters -- both will be maintained for the foreseeable future.

Second, Perl 6 is a significant change to Perl, with far more features and
somewhat different syntax. People will want to change for the features.
Running Perl 5 code from inside Perl 6 works by calling out to libperl, which
runs a real version of Perl 5. Perl 5 will still be popular due to ubiquity,
access to CPAN modules, and things like CPAN Testers.

So it's a choice for the developer, to develop in a new language that just
happens to be Perl-flavored, or to go with any other language. Not really a
crisis.

------
vegabook
My problem with this post is not its factual accuracy. It's factually
accurate, downright impressive.

My problem is with its premise. That premise is that Python 2.7 people need to
be somehow educated. To be shown some kind of light. It's the same premise
that the project leaders have been going on about for 7 years. "Can't you see
how much better this is?". Worse: "are you 2.7 people stupid, or what?".

It hasn't worked.

Why hasn't it worked? Not because 2.x people are slow or uninformed. They're
very well informed. They assess the merits and downsides. They've had 7 years!

The reason is a combination of inertia, but also, many people actually think
that in many ways, 3.x is a _regression_. If you don't need Unicode, Unicode
is a huge pain in the xxxx. I was just having to mess with "b"s everywhere
_today_ on strings over msgpack to a non-pythonic endpoint. Lazy ranges (can
also be) a huge pain in the b __t. So I must move to 3.5. For what? Type
annotations? Asyncio? I 've been using (the highly impressive) Tornado for 3
years on 2.7.

Now google brings out the brand new TensorFlow. On 2.7. "But porting to 3 is
their #1 priority" I'm told. Okay cool. You wait. I won't.

So the advances of 3 meet the regressions of 3. Even if you believe the net is
positive in 3's favour, that net is not nearly enough to persuade people with
actual lives outside of computer science, to port years of code, and more
importantly, to port their brains to work with the new dispensation. Python is
a language for people who want to get things done. 2.7 gets things done. Zero
problems. For many people, that's the killer feature.

------
emodendroket
Every programming language, programming language update, and programming tool
since the dawn of time claims to make it easier to produce high-quality
software.

~~~
Amorymeltzer
>Brainfuck

Seriously though, the point is well taken. The right tool for the right job
will always apply, and I like to think most developers and programmers
acknowledge that there are very few tools that should be used in every
opportunity and by every person.

~~~
Vendan
Interestingly Brainfuck has a use, though it is an obscure one. It's proven to
be turing complete, and has a rather trivial set of instructions and rules. If
you can write an interpreter for it in another language, you prove that
language to be turing complete as well.

------
lyschoening
Python 3 is so far ahead now as a language that it surprises me anyone would
even consider it for a new project. Among other things, Python 3.4 and 3.5
have added support for coroutines that provide a whole new level of utility to
the language. Meanwhile, Python 2.7 is a study in limitations to anyone who
has followed up on Python 3.x developments.

------
tibbon
I still don't understand what happened here historically, was there ever an
upgrade path or way to make this a smooth transition? I can't think (surely
there is) of another language that had such a hard-breaking version change
that still persists 10 years later as a fracture across the community.

~~~
maxerickson
It hasn't been 10 years. There were known IO performance regressions at the
time 3.0 was released, nobody involved in releasing it would have said to use
it in production right away. 3.1 was released ~6 years ago:

[https://www.python.org/download/releases/3.1/](https://www.python.org/download/releases/3.1/)

(Even if the above is deemed BS, the release of 3.0 was 7 years ago)

Many of the 3.0 features can be switched on in 2.7 and there were some
attempts to automate as much of the code change as possible (but people ended
up preferring to write code that runs on both 2.7 and 3.x, but I suppose that
then is not really evidence of a fracture).

~~~
saurik
I remember quite distinctly when the Python 3000 manifesto was released just
under ten years ago, in April of 2006. That is when the line in the sand was
drawn and the key mistakes were made that caused the "schism" in the
community. What the Python community was screaming for was a fix for the GIL
and the other performance issues in Python, not minor changes to Unicode
handling that were maybe awkward but perfectly possible to get right in Python
2.6.

Google seriously spent tons of effort at the time trying to remove that GIL.
They were one of the biggest proponents of Python at the time, and frankly
they were part of what made it so successful. With their work on Unladen
Swallow not making meaningful progress and the Python core developers
concentrating on Python 3000, making it clear that they don't even care, it
isn't a wonder that Google was hedging their bets by hiring Rob Pike to work
on Go, which many now see as most directly being a competitor to Python, and
which has sapped a lot of people who would potentially be Python users.

Meanwhile, the broken release of 3.0 needs to be blamed for part of the
problem, not used as a reason to delay the historical date of fracture: a lot
of things were broken in 3.0, including some basic things that Python got
wrong in Unicode. The performance regressions were not quickly fixed, making
people hesitant of the benefits of Python 3, and the Unicode issues (which
were not fixed until years later, when they added the round-trip-safe Unicode
conversions; but even this is a workaround, as filenames are defined to be
strings of bytes by the filesystem) were ironic as the whole point of Python 3
was to somehow be better at dealing with Unicode :/.

And you seem to be forgetting that the real problem was not the features added
in 3.0 but the features _taken away at the same time_ that made it impossible
to write reasonable code that ran on both 2.7 and 3.0 even for extremely
simple cases like "catches an exception". They only just a year or so ago have
started to crack their party line of "shut up and upgrade to 3: it is better
and you are wrong" and add some backwards compatibility features to 3.x, such
as supporting the u prefix (which was the absolute dumbest thing they could
have removed).

------
snake_plissken
On a tangential note, no pun intended, I am a little confused. Why would you
ever want compare in the manner of "TrickyAngle(6) < TrickyAngle(5)"? I can
understand something like "trickyAngle_A.degrees < trickAngle_b.degrees" but
when comparing instances of a class like that, when would one ever
be...greater than the other?

~~~
angelbob
Often, an instance of a class represents a mathematical entity (vector,
matrix, imaginary number, mathematical set, et al) where less than might be a
fundamentally reasonable operation, especially in some specific context.

His example is using it as an angle, where comparing two of them is
conceptually pretty sensible.

If you pretend it's a structure, sure, you'll need to extract primitive data
types out of it before doing anything with it. But if you want it to behave as
a higher-level abstraction, reimplementing less-than (say, for comparing the
vector magnitude) at every call site isn't great.

~~~
philh
(This is completely beside the point.)

> comparing two of them is conceptually pretty sensible.

Well, there are a bunch of sensible ways to do it, depending what the angle
represents. You might not want to privilege any of them over the others
directly in the class.

Is it a point on the unit circle? It doesn't make much sense to compare
(sqrt(2), sqrt(2)) to (-1, 0).

Is it an angular distance to travel from point A to point B? Then you want 355
and -5 to both be less than 10.

Is it an amount that a screw has to be rotated? Then you can't take mods, so
720 > 360 > 0.

Do you have a robot that can only turn anticlockwise? Then maybe 5 < -10 <
355\. This is the comparison implied by the implementation in TFA
(self.degrees = degrees % 360), but it's pretty obscure.

------
Alex3917
Given that even a relatively inexperienced developer can easily port 2,500+
lines of Python 2 to Python 3 per day, there's really very little reason for
anyone to still be on Python 2 regardless of the benefits or lack thereof of
Python 3. This is especially true if you're not trying to take advantage of
all the performance benefits of Python 3 right away, and are content just to
wrap iterators in list() or whatever just to get the functionality working the
same without much effort.

~~~
sago
It's libraries rather than porting.

Funnily, though, I just thought 'yeah there's that library I use, they never
ported that', for one of my codebases. Just looked it up and they now have
ported it. So I guess it's time for me to do the same. I wonder what
proportion of (actually used) libs are Py 2 only still.

~~~
ensignavenger
At this point very few 'actually used' (meaning, used by more than a handful
of organizations at most) are Py2 only. There are a few still in the process
of porting, and a few that will never be ported due to being replaced (but are
still somewhat popular for one reason or another.)

For those who don't know:
[http://python3wos.appspot.com/](http://python3wos.appspot.com/)

~~~
thrownaway2424
People are still releasing brand-new Py2-only libraries to this very day. This
is especially true in science, math, nlp, ml, etc.

~~~
ensignavenger
Yes, and I kinda think it is silly, but whatever. Care to share any examples
of recent releases? I know Google's TensorFlow was/is Py2 only, but a Py3
release is imminent. Google has an unfortunate habit of using Py2... I can
understand they have their reasons... it is a bit irritating though :)

(Edit: Not that I care what they use internally... but sometimes they release
a really cool open source library and it is Py2 only... arr! But at least they
are sharing, so I can't really be too upset :)

~~~
progval
snap-python. Development started in 2013, and yet they refuse to support
Python 3: [https://github.com/snap-stanford/snap-
python/issues/52](https://github.com/snap-stanford/snap-python/issues/52)

~~~
eeZi
So you'll have to convince them. Maybe they did not realize that SWIG supports
Python 3 nowadays?

There's really no good reason not to support Python 3, and projects which
refuse will at some point be forked.

~~~
daveguy
Nah, just do the smart thing and stick with python 2.7.

------
rasz_pl
Majority of people dont care about new shiny, they care about things that
broke or changed. Probably 90% of them started complaining because print
statement is a function :).

Python 3 insistence on unicode hurts my brain. I had a 'pleasure' of writing
Python 3 script manipulating data produced by Python 2 (custom pickle). Ended
up reimplementing whole Python 2 pickle library by hand, because apparently no
one imagined a use case involving reading raw bytes into a buffer.

~~~
DasIch
The problem is really that Python 3 isn't new and shiny. It's an attempt to
improve some downsides of Python 2 and some parts did actually get better but
many parts didn't although they easily could have been improved, some parts
even got worse.

Python 3 provides no real benefit to an experienced Python developer. So
considering all the things you could possibly do, switching to Python 3 is not
switchting to a new and shiny thing, it's just a bad decision.

If you really want to switch to something new and shiny, there are now many
more interesting language options. Modern Javascript has copied so much from
Python, you can feel very much at home there. If you care about concurrency,
you have Go. If you care about concurrency and care about using a language
that's well designed or just want performance, there is Rust.

~~~
lqdc13
async lib is really really nice. You can easily issue async requests now.
Also, a bunch of useful utilities were improved like shutil.

~~~
DasIch
The idea behind asyncio is nice. The API is mostly nice. The new async/await
syntax that has been added mostly with asyncio is great. The documentation
however is a horrible mess and the implementation could almost certainly be a
lot better. Now it's in the standard library though...

David Beazley recently held a great talk on this very topic, in which he goes
into these issues in more detail:
[https://www.youtube.com/watch?v=lYe8W04ERnY](https://www.youtube.com/watch?v=lYe8W04ERnY)

------
gdulli
Complaints about a language translate automatically to low-quality software
the same way micro-optimizations automatically translate to fast software.

In the real world, software depends significantly more on the properties of a
developer or a team. Building software is about people more than it's about
tools.

------
brianmcconnell
Dealing with Unicode in Python 2.x is a _nightmare_. So if you need to go
beyond ASCII, Python 3 is a huge improvement. On the downside, if you want to
use tools like App Engine, you're still stuck with 2.7 for now, but hopefully
that will change.

~~~
yarrel
Python 2's handling of Unicode basically isn't. That's as much the fault of
third party libraries as the core language, but it is a real and constant time
suck.

I'm sure I hit Unicode problems in Python 3 a few years ago as well, but if
current versions are better that would be a sufficient reason for switching.

------
yeukhon
This is excellent. The first one is totally unknown to me. I wish there is a
comprehensive changes between 2.7 and 3.X with code, release notes is okay but
falls under different version and hard to grasp at once.

It's really hard to keep up with language changes and implementation changes.

EDIT: I am so surprise at the number of downvotes in this HN thread. I bet
there is some haters out there today :-)

~~~
maxerickson
The first one was a headline change in the Python 3000 release notes:

[https://docs.python.org/3.0/whatsnew/3.0.html](https://docs.python.org/3.0/whatsnew/3.0.html)

The other items in the article are also mentioned there, but not as headline
items. The great majority of behavioral changes from 2.7 to 3.x should be
listed in that one document, there was a freeze on language changes for
several of the 3.x releases.

~~~
yeukhon
That level of code demonstration from the author is more comprehensive than
the documentation in what's news.

A lot of the PEPs are way too verbose for a quick bite. PEP are great for a
weekend read, but for a quick summary, OP does a better job.

~~~
maxerickson
I wasn't saying that you should be satisfied with just the release notes, I
was pointing out that you were overstating the difficulty in finding an
overview of the changes that went into Python 3.

There are lots of other changes since then, but most of them are additions
(that don't directly impact old code) or to libraries or whatever.

------
nnq
The whole 2 vs. 3 debate would simply have not existed if the Python core devs
would have simply _refused_ to backport tweaks and fixes from 3 to 2 and would
have _forcefully deprecated_ 2.x immediately after releasing 3.0, even if it
was inferior to 2.x at first release.

Guido should have used his power to force the move forward down people's
throats, because that's the _responsibility of a BDFL._ The _D_ is there for a
reason, and its exactly in this cases that the power of the Dictator role
should have been used.

Communities rarely move forward on their own if left to decide democratically:
they need o be _forced_ or _tricked_ into moving forward by _individuals with
vision!_

...heck, I'm even starting to like the nodejs folks for their "shove the
future down people's throats" attitude :)

~~~
fuhrysteve
I think it would have been more prudent to have implemented an iterative
approach:

Python 2.8: \- boring easy to fix changes like division, print function,
exception handling syntax, removal of iteritems() / etc

Python 2.9 \- library reorganization (urllib2 & urllib, etc)

Python 3.0 \- unicode stuff

Most organizations that have been lingering at 2.7 for 5+yrs would have long
since migrated to 2.9, and would thus be half way to 3.x in terms of backwards
compatibility.

Now instead, everyone has to introduce the better part of a decade's worth of
backwards compatibility changes at once, or be left in the dust. Hardly a fair
choice.

~~~
maxerickson
Some of your Python 2.8 exists as from __future__ imports added to various 2.x
releases.

[https://docs.python.org/2/library/__future__.html](https://docs.python.org/2/library/__future__.html)

(in versions where the new behavior is the default, the import does nothing
and is not an error)

------
Grue3
I'm sorry, but given how much high quality software is written in Python 2,
examples of high quality software written in Python 3 more easily would do a
better job proving the central thesis of the article than pointing out design
defects of Python 2 fixed in Python 3. Because at the end of the day, there
are still plenty of design defects in Python 3 (or any other language) that a
coder might trip over. I mean who is to say that new yield functionality of
Python 3 wouldn't lead to hard to understand spaghetti code? Or the new way of
handling Unicode isn't worse than the old way? Listing concrete projects that
benefitted from being written in Python 3 rather than 2 would be much more
convincing.

~~~
minimaxir
> _I 'm sorry, but given how much high quality software is written in Python
> 2_

The reason for that isn't "Python 2 is intrinsically better than Python 3,"
though. It's the sheer inertia of a language whose last minor version (2.7)
was released _five years ago_ and the persistent meme that Python 3 is buggy
and unusable, despite clear advantages as noted in the article and the added
compatibility of popular Python 2 packages in recent years.

As with hardware, Python 2 will only die when the top packages _completely
drop support_ for it, and it wouldn't surprise me if that happens sooner than
later. (Django, for example, will be dropping Python 2 support in 2017:
[https://www.djangoproject.com/weblog/2015/jun/25/roadmap/](https://www.djangoproject.com/weblog/2015/jun/25/roadmap/)
)

~~~
legutierr
Why refer to these as two separate languages? Right now, the vast majority of
Python's most popular libraries and packages support both 2.7 and 3.4+ with a
single code base. We are a Python shop, and we are doing the same with all our
new projects as well. There's a little bit of extra awareness you have to have
to do certain things (metaclasses, for instance), but the overhead is no more
onerous than, say, following well-defined coding conventions.

------
klunger
It doesn't help that Mac books come with 2.7 installed. For someone starting
out (Python is often used as a teaching language in CS101-esque classes),
figuring out how to get one's machine to use 3 might seem really
difficult/impossible.

~~~
sigzero
Almost everyone will say "Use homebrew". I don't think it will that difficult.

~~~
tim333
Yeah brew install python3 seems to work. You then just type python to run 2
and python3 to run 3. The compsci course I did was in Python 2.

------
avoutthere
> Python 3 makes it easier to develop high quality software

That is, unless said software needs to include a popular library that has not
been ported.

~~~
eeZi
There aren't many unported popular libraries left. Actually, the only one I
remember off-hand is Twisted, and they're working on it.

------
pbhowmic
Library compatibility is definitely an issue. You still have some very
influential libraries that are not Python 3.x compatible. But an oft
underestimated issue is the number of Py3 improvements that have been
backported to Py2. For example absolute imports. That has made the case for
moving to Py3 harder.

~~~
takeda
Argh, I don't like this argument.

There's really barely anything that is python2 specific, most of the things
that weren't ported is no longer being maintained.

I think the main reason you should start moving to python3 is that it will be
discontinued. Python 2.6 was EOL in 2013, 2.7 they've been more generous and
you have 4 more years, originally it supposed to be 2015.

There's no good reason to stick with 2.7, if you have some legacy apps there's
nothing preventing you from having Py2 and Py3 installed side by side.

If you need to write libraries that share code, it's much easier to write the
code in Py3 and then make it backwards compatible with use of from __future__
... imports and six module.

I feel like people who still complaining about the difficulties did not
actually tried Python 3. Py3 is much more enjoyable language to write in.

~~~
pbhowmic
TensorFlow is just the latest library that is Py2 only. App Engine is Py2
only. The bigger issue is the 2 biggest weakness with Py2 that were not
addressed in Py3 (CPython version at least) - GIL & JIT. JIT is addressed more
or less by PyPy but it is Py2.7-compatible, not Py3 compatible. Addressing
this in the standard CPython implementation can make for a very compelling
case for move to Py3. Otherwise, it does not buy you much.

~~~
takeda
TensorFlow and App Engine are both released by Google which prefers Py2
because of the FUD, although regarding TF hopefully it won't be for too long.
The first issue created on GitHub[1] is basically about adding Py3 support.

Regarding GIL and JIT. Those problems are mostly performance related and not
easy. As you mentioned GIL is available everywhere so it's not a good argument
regarding py2 vs py3.

As for JIT you get it with PyPy which by itself is not 100% compatible with
CPython (for example as of now majority of python modules written in C simply
won't work).

Although they do have PyPy compatible with Python 3 although it is not as
stable, but since Py3 is picking up hopefully it will be becoming more
popular.

For me, it's the other way around, I have not used PyPy primarily because it's
compatible 2.7 and I don't use Python for performance, but if I could get
performant Py3 implementation then why wouldn't I want to use it?

[1]
[https://github.com/tensorflow/tensorflow/issues/1](https://github.com/tensorflow/tensorflow/issues/1)

------
EvanPlaice
Python 3 is great, but that doesn't matter.

The ecosystem is rotting for 2 reasons.

First, there's no easy way for library developers to maintain a codebase that
supports both 2/3 development in parallel. Yes, it's easy to use a 2to3/3to2
tool but unlike transpilers in Javascript the output code may still require
fine-tuning after the tranform.

This could be solved by adding preprocessor support to python (ie for
conditional loading of code) but GvR is adamantly against this approach use to
the way many devs write unmaintainable code in c via the preprocessor.

I actually published an OSS project called pypreprocessor that was supposed to
solve this issue. It works to add preprocessor conditionals to code but won't
work with both 2/3 code in the same file because there's no hook to inline
code before lexer runs and throws syntax errors.

Second, package management in python still sucks. Do you use distutils,
distutils2, setup.py, etc? There's no single standardized approach that
everybody agrees on and each tool follows a unique approach or needs to be
supported because of legacy code.

Unlike the Ruby, Javascript ecosystem where package management and publishing
is relatively straightforward/easy, it's an absolute PITA to publish packages
to PYPI.

Back in 2011, the answer was. Just wait 5 years for everybody to adapt their
libraries to support Python 3. 5 years later, nothing has changed. The
existing libraries don't want to piss off users by dropping Python2 support
and maintaining two separate branches of the code in parallel sucks. So, since
most everybody that uses python in production still relies on Python2, Python2
is still the default.

The library ecosystem makes the platform. The tooling sucks so library devs
don't want to make the switch.

Until there is a major cultural shift python devs have 2 options. Use a better
version of the language without the support of a mature library ecosystem, or
use an outdated version of the language with a rich ecosystem.

------
anewhnaccount
And how many subtle bugs will be introduced during porting software for Python
2 to Python 3?

~~~
m0th87
We ported a major production site from python 2 to 3 a year ago. Exactly one
bug has come up - something to do with unicode encoding on a relatively minor
part of the site. Thanks to 2to3, the concerns for bugs coming up in porting
are way overblown.

~~~
brbsix
The only insidious issues I've encountered with porting apps have been related
to Unicode as well. A lot of old Python 2 code is (what appears to me) very
hackish compared to the elegance that is Python 3.

~~~
qfwfq_
I've seen quite a bit when porting a statistical library that used Python 2's
default floor/int division behavior for quite a few operations.

Sometimes, though, the _2_ version had bugs because of this behavior. So, the
bugs were both subtle and bi-directional. I definitely fault Python 2 for
allowing that practice, and am glad we're now using Python 3.

------
osullivj
For me it was these two...

1\. Calling the next( ) builtin instead of .next( ) method on an interator or
generator.

2\. .items( ) on a map in 3 is like .iteritems( ) in 2. Which means that nasty
short cuts like map.keys( )[0] no longer work.

Oh yeah, and print( ) is a function :)

~~~
lqdc13
I think a bigger issue with keys() is that now the order is non-deterministic.
So people may have relied on it not being in any particular order but being
the same order. These are the kinds of bugs that are difficult to detect.

~~~
dalke
I don't understand this comment. The hash method changed under different
releases of Python 2.x, enough that was had to change our doctests to ensure a
consistent order. So as far as I'm aware, the only guarantee is that calling
.keys() and calling .values() will give you the terms in the same order, so
long as there hasn't been a modification in the middle.

~~~
lqdc13
Ok, try running this in a program like so:

    
    
        d = {chr(i):i for i in range(65,91)}
        print(d)
    

Do it with python2 and python3. You'll see that the output in python3 changes
every time.

If someone was relying on consistent ordering, they're going to have a bug.

Python2's ordering is deterministic[0]

[0][https://docs.python.org/2/library/stdtypes.html#dict.items](https://docs.python.org/2/library/stdtypes.html#dict.items)

~~~
dalke
Okay, we're talking about the same thing. As the documentation points out:

> If items(), keys(), values(), iteritems(), iterkeys(), and itervalues() are
> called with no intervening modifications to the dictionary, the lists will
> directly correspond.

If you restart Python, you have broken the correspondence.

You'll note that either the documentation is incomplete or your interpretation
is incorrect, as the most recent versions of 2.6 and 2.7 will use a randomized
hash table when the -R flag is enabled:

    
    
        % ~/Python-2.7.10/python.exe -R x.py
        {'M': 77, 'L': 76, 'O': 79, 'N': 78, 'I': 73, 'H': 72,
         'K': 75, 'J': 74, 'E': 69, 'D': 68, 'G': 71, 'F': 70,
         'A': 65, 'C': 67, 'B': 66, 'Y': 89, 'X': 88, 'Z': 90,
         'U': 85, 'T': 84, 'W': 87, 'V': 86, 'Q': 81, 'P': 80,
         'S': 83, 'R': 82}
        % ~/Python-2.7.10/python.exe -R x.py
        {'Z': 90, 'Y': 89, 'X': 88, 'W': 87, 'V': 86, 'U': 85,
         'T': 84, 'S': 83, 'R': 82, 'Q': 81, 'P': 80, 'O': 79,
         'N': 78, 'M': 77, 'L': 76, 'K': 75, 'J': 74, 'I': 73,
         'H': 72, 'G': 71, 'F': 70, 'E': 69, 'D': 68, 'C': 67,
         'B': 66, 'A': 65}
    

I can totally understand how people expect an invariant order. As I pointed
out, our regression code broke in the 2.x series because we relied on
consistent ordering, and CPython never made that promise. But what I quoted
above is the only guarantee about dictionary order. Everything else is an
implementation accident.

Nor is it the only such implementation-specific behavior that people sometimes
depend on.

    
    
      >>> for c in "This is a test":
      ...   if c is "i": print "Got one!"
      ... 
      Got one!
      Got one!
    

That's under CPython, where single character strings with chr(c)<256 use an
intern table. Pypy doesn't print anything because it doesn't use that
mechanism.

Note that 'is' testing is also faster:

    
    
        % python -mtimeit -s 's="testing 1, 2, 3."*1000' 'sum(1 for c in s if c is "t")'
        1000 loops, best of 3: 893 usec per loop
        % python -mtimeit -s 's="testing 1, 2, 3."*1000' 'sum(1 for c in s if c == "t")'
        1000 loops, best of 3: 1.01 msec per loop
    

This extra 10% is sometimes attractive.

~~~
lqdc13
Sure, but why did you enable the -R flag?

We are talking about the default way of doing things in the most commonly by
far used implementation.

I'm not saying someone should have relied on the specific ordering or that the
code that does rely on it is a great way of doing things.

CPython2 did make that promise -

    
    
        CPython implementation detail: Keys and values are listed in an arbitrary order which is non-random, varies across Python implementations, and depends on the dictionary’s history of insertions and deletions.
    

In other words, the order should be the same no matter how many times you
restart the application.

It is a subtle source of bugs since it always worked in each specific version
of CPython2 without the -R flag.

~~~
dalke
"why did you enable the -R flag?"

Because either the documentation means to include -R in the description, in
which case your interpretation of the documentation is incorrect, or the
documentation is incomplete because it doesn't describe a valid CPython 2.x
run-time. Either way, it indicates that the difference isn't, strictly
speaking, a Python2/3 issue.

"an arbitrary order"

Where does it say that the arbitrary order must be consistent across multiple
invocations? Quoting from
[https://docs.python.org/2/using/cmdline.html#cmdoption-R](https://docs.python.org/2/using/cmdline.html#cmdoption-R)
:

> Changing hash values affects the order in which keys are retrieved from a
> dict. Although Python has never made guarantees about this ordering (and it
> typically varies between 32-bit and 64-bit builds), enough real-world code
> implicitly relies on this non-guaranteed behavior that the randomization is
> disabled by default.

I totally understand your point. I remember the debates about how this would
break code. But it's there to mitigate algorithmic complexity attacks against
an every increasing attack surface. This was the best solution they come up
with, along with a migration path to the new default.

------
arbitrage
> It's the kind that easily sneaks its way past the most vigilant unit tests

If your unit tests are the most vigilant, you'll test the output of that
function for just such a comparison.

------
jessaustin
Nothing about unicode handling?

~~~
the_mitsuhiko
Unicode works just fine in 2.x for people that give a shit :)

~~~
ptx
It's a lot easier to work with in 3.0, though.

For example, xmlrpclib in 2.x will return either _str_ or _unicode_ depending
on whether the particular piece of data it's returning happens to contain non-
ASCII characters. In 3.x it always returns a unicode string.

~~~
DasIch
The problem is that in Python 3 some cases aren't easier, they've become
impossible to do properly. Dealing with paths is a good example where Python 3
has created a huge mess. IO specifically stdin/-out/-err is another area in
which Python 3 has created massive problems.

~~~
ptx
I believe they fixed that in 3.1, so it's no longer impossible:
[https://www.python.org/dev/peps/pep-0383/](https://www.python.org/dev/peps/pep-0383/)

Regarding the huge mess, that exists with or without Python 3 if filenames use
unknown, incorrect or inconsistent encodings. To treat a path as as text, e.g.
to show it to a human or send to another system, you have to know its
encoding. Python 3 and GTK (with its G_FILENAME_ENCODING and
G_BROKEN_FILENAMES) make this clear - some other software (like Python 2) just
silently uses and propagates the broken data.

------
pbreit
Question is: could they have fixed these problems without breaking everything
else?

~~~
webmaven
TL/DR: No. Many, _many_ of the changes are backward incompatible with the
existing Python 2 syntax and APIs.

Any changes that _could_ be made in some compatible way have largely been
backported to the Python 2.x versions (the latest stable version of which is
Python 2.7.10) that have been released more-or-less in parallel with the 3.x
line (search for 'backport'): [https://hg.python.org/cpython/raw-
file/15c95b7d81dc/Misc/NEW...](https://hg.python.org/cpython/raw-
file/15c95b7d81dc/Misc/NEWS)

Enough such has been done that you _can_ write Python code that runs in recent
versions of _both_ Python 2 and Python 3 (which is very important for 3rd-
party library maintainers that want/need to support both it in a single
codebase), but to do that you will be forgoing most of the productivity and
'niceness' benefits of the sort that are described in the OP.

------
yarrel
Is it "people use Python 2"?

------
sinxoveretothex
Slightly tangential, but I wish this blog would date its posts.

Reading "If you're starting a brand-new application today, there are plenty of
valid reasons to write it in 2 instead of 3. There will be for a long time."
on the same day it was written is not the same as 6 months or a few years down
the lines.

I don't actually know when this was written except for the copyright:
2014-2015, so it can't be more than a bit short of 2 years ago.

~~~
seliopou
I remember seeing a retweet in my stream a couple months ago where somebody
made the suggestion of not dating blog posts so as to make them seem less
ephemeral. I think the logic went that if the writing isn't tied to a single
moment in time, then it'll become timeless.

It's one of the more irrational and idiotic suggestions I've ever come across.
One of, if not _the_ most important piece of metadata for anything that has or
will ever exist is its creation date. In particular for writing, putting it in
a historical context usually makes the piece more powerful and increases your
understanding of the subject. If it's bad writing then it's not going to have
a chance anyway. Sorry to say but that may be true of the post in question. I
was under the impression that due to poor Python 3 adoption, Python 2.7 would
continue to be supported.

I second OP, please date your blog posts.

------
zingermc
Your title is a little misleading, since you actually discuss three
differences.

~~~
trextrex
I think the OP means the single main difference is "Python 3 makes it easier
to develop high quality software." and gives three examples of this.

~~~
badloginagain
Which still doesn't make much sense. One thesis, "better software", three
supporting arguments.

It's ok to be pedantic, but only if you're correct about the thing you're
being pedantic about.

------
thrownaway2424
Py3 is a completely different language that happens to share the same name as
Py2. If you want to talk about typed comparisons you might as well mention C++
and Java and Go and Rust, because you might just as easily move from Py2 to
any of them, as from Py2 to Py3.

~~~
eeZi
Not true. Not only can most of the code be used verbatim, but the libraries
and APIs are still the same - which would constitute most of the porting
effort to another language.

A Python 2 dev can learn Python 3 in a day.

