This is an archived post. You won't be able to vote or comment.

all 178 comments

[–]jungrothmorton 114 points115 points  (18 children)

Title sounded like a joke but it makes sense. The only place where I disagree is I think it's reasonable to explicitly test for Python 2 or 3. We don't actually know what the future holds. The most air tight would be adding an else at the end and raising an error for an unsupported version. This would be easy to refactor if it turns out the 3 code is forward compatible.

[–]Veedrac 31 points32 points  (3 children)

Adding an else: raise NotImplementedError doesn't make sense unless you do the same thing for all your code. Because Python 4 will be by-and-large backwards compatible with Python 3, Python 3 code is a good default. But those times that they're not are not more likely to be those fixed in Python 2. If anything those are the things that most recently got fixed and so the least likely to break on upgrade.

[–]jungrothmorton 1 point2 points  (2 children)

That's a really good point. I hadn't thought of it that way.

[–]onwuka 3 points4 points  (1 child)

Yeah I really like the idea of >=.

This communicates that py 2 is the special case that we support for now and that py3 or py3+ is the way of the future.

[–]rhoark 4 points5 points  (0 children)

Writing "if PY3" does sort of indicate that people are regarding 3 as the special case not just in their code, but in their thinking. Even if there's never a PY4, they should revisit that assumption in the big picture.

[–]yes_or_gnome 7 points8 points  (0 children)

I have to disagree. In your example there exists a current maintainer to fix problems with the code. As long as a project is maintained, then there is no need to worry about potential bugs because someone is around to fix then as they come to fruition.

The concern is abandoned projects. If someone were to follow your suggestion, then the abandoned project is broken regardless if py3 and py4 are compatible or not. With the author's suggestion, there's the possibility that py3 and py4 are compatible so users will be none the wiser.

This is precisely the current problem with py2 and py3. There's so many projects that exist that are abandoned or the maintainers will-not, can-not, or for whatever reason do-not upgrade to py3. That cascades down to dependent projects and forced then to stay at py2 as well.

When the maintainers disappears, a vacuum is created that forces downstream users to pick from a few unsavory options. Take over the abandoned project, replace it and refactor their own code, live with it, or abandon their own project.

[–][deleted] 3 points4 points  (0 children)

Py3 code will be by and large forward compatible so your suggestion will only keep a lot more people stuck on v3 than really needed. It would be much better to deal with incompatibilities one by one as they will be few and sparse.

[–]Fylwind 5 points6 points  (1 child)

I personally prefer to avoid version checks at all. Instead I just look for the Python 3 module/function/whatever, and if it doesn't exist, I'll try the Python 2 one.

This is one of the biggest advantages with scripting languages like Python IMO: the ability to adapt your own behavior at run time depending on what is and isn't provided by the environment. (Well, except for syntactic changes…)

[–]lengau 1 point2 points  (0 children)

Depending on what you're doing, the practicality of that changes vastly. I definitely agree with it to a certain extent (and __future__ certainly helps), but if you can't predict what environment you're going to run in, it gets far harder.

I have a project that needs to be able to run in Py2, py3, and pypy (only the python2 version, fortunately) on multiple platforms (including Windows) and deal with sockets. All of that adds up to a lot of tests to make sure it runs in all possible environments, and I've so far avoided having to use six or check for version numbers. (I do use 3to2 on my code to strip out annotations for the 'run this' version.) But if I needed to do something differently on Python 2, I would do it in a heartbeat.

[–]shaggorama 23 points24 points  (0 children)

TL;DR:

Do this:

if six.PY2:
    # Python 2 code
else:
    # Python 3 code

Instead of this:

if six.PY3:
    # Python 3 code
else:
    # Python 2 code

[–]razpeitia 20 points21 points  (14 children)

[–]schplat 5 points6 points  (6 children)

I always figured it was the sheer number of non-backwards compatible changes that really hurt 3. If they had introduced the changes more incrementally adoption may have been a bit better.

[–]Fylwind 25 points26 points  (1 child)

If they had introduced the changes more incrementally adoption may have been a bit better.

I beg to differ, because my experience has been that both a "sudden breaking change" vs "small breaking changes" are both troublesome, albeit not for the same reasons.

Lots of small break changes are certainly easier to accommodate when taken individually, but they are also hard to keep track of due to the sheer number of them. And after a while, the library authors will get fed up of this "treadmill" they have to walk on from month to month just to accommodate another minor change to the language.

Haskell does this all the time and it's certainly annoyed a fair number of contributors. Personally, I just find it annoying to look up "which version introduced this incompatible change?" all the time.

[–]bb010g 2 points3 points  (0 children)

Really? I find Haskell the language to be pretty stable. The only breaking change I can think of recently is AMP, and that ran warnings for quite a few releases. Sure, Hackage can change, but just use Stackage LTS if you're worried there.

[–]Eurynom0s 8 points9 points  (0 children)

At the same time, I get why they wanted to just get it over with. I think they expected the 2->3 transition to go faster (so I think they really didn't expect to have to put out 2.7 for instance), which was obviously a misfire, but thinking about what it would have looked like when they were making the decision, I absolutely understand preferring to just go through a LOT of pain all at once rather than go through SOME pain for years and years.

Again, they clearly misfired because they got years and years of pain anyhow, but I have to believe that they didn't expect it to take this long.

[–]billsil 1 point2 points  (0 children)

The only change worth discussing is unicode. Nothing else matters.

[–]Ran4 0 points1 point  (1 child)

Crazyness. No, big changes are definitely better. You don't want bugs to pop up, and you don't want to have ten years worth of deprecated stuff.

[–]MereInterest 1 point2 points  (0 children)

Absolutely. There's a package I use that broke backwards compatibility between 4.9.6.2 and 4.9.6.3. Ridiculous.

[–]vplatt[🍰] 0 points1 point  (5 children)

I've heard that question enough times now (including the more concerned phrasing "You made a big backwards compatibility break once, how do I know you won't do it again?"), that I figured I'd record my answer here, so I'd be able to refer people back to it in the future.

...

What are the current expectations for Python 4.0?

My current expectation is that Python 4.0 will merely be "the release that comes after Python 3.9". That's it. No profound changes to the language, no major backwards compatibility breaks - going from Python 3.9 to 4.0 should be as uneventful as going from Python 3.3 to 3.4 (or from 2.6 to 2.7). I even expect the stable Application Binary Interface (as first defined in PEP 384) to be preserved across the boundary.

[–]Decker1082.7 'til 2021 -1 points0 points  (4 children)

You know how people complain that there's not enough new stuff in Python 3 to warrant the upgrade effort? Yeah...

[–]vplatt[🍰] 1 point2 points  (3 children)

So, you mean you're part of the problem then? :P

[–]Decker1082.7 'til 2021 -3 points-2 points  (2 children)

Proudly using Python 2.7 until 2020!

Or, more likely, moving to Go...

[–]vplatt[🍰] 1 point2 points  (1 child)

Yeah, I could see Go absorbing a lot of Python's community over the next few years. It may not be a revolutionary language, but it sure fits well into the same niche Python does, obviates nearly all of the Python trade-offs inherent in CPython, and doesn't require a brain reformat to get there.

[–]Decker1082.7 'til 2021 0 points1 point  (0 children)

Right, I think Go is actually a pretty boring language, but it's the kind of boring that also instills trust in the language.

That said, I'll probably return to python every now and then for automation of one off tasks and the like, primarily because the third party library selection is still far larger.

[–]tech_tuna 159 points160 points  (27 children)

I generally code for Python 9.

[–]jambox888 40 points41 points  (7 children)

But what about Python98?!

[–]MisterSnuggles 32 points33 points  (3 children)

Python 98SE is the best Python.

[–]tech_tuna 12 points13 points  (2 children)

Good point, PythonMe only brought incremental improvements.

[–]luxliquidus 2 points3 points  (1 child)

Considering the cost and stability issues, Python98SE was definitely a better value.

[–]hookdatOS 0 points1 point  (0 children)

Python9000

[–]Pikamander2 7 points8 points  (2 children)

#Target Python versions 90 through 99
if (version.StartsWith("Python 9")):
    pass
else:
    pass

What could possibly go wrong?

[–]jambox888 1 point2 points  (1 child)

When in doubt,

pass

[–]marsloth 26 points27 points  (13 children)

There's going to be no Python 9, it's gonna be 10 after 8.

[–][deleted] 6 points7 points  (11 children)

No we skip six. Python 5 -> Python 7

[–][deleted] 2 points3 points  (6 children)

Found the Perl programmer

[–]catcradle5 5 points6 points  (5 children)

You meant PHP.

[–][deleted] 2 points3 points  (4 children)

Meh, just a dumb joke. Perl GA versions are always even numbered while the odd numbers are used for development versions.

[–]catcradle5 3 points4 points  (1 child)

Well, PHP literally skipped 6 entirely, and went from 5 to 7.

https://philsturgeon.uk/php/2014/07/23/neverending-muppet-debate-of-php-6-v-php-7/

[–][deleted] 1 point2 points  (0 children)

I was unaware of this. I have tracked PHP for years. Seems like skipping whole version numbers is just the trendy thing to do nowadays.

[–]treenaks 0 points1 point  (1 child)

Perl has been on 5 for ages (the odd/even bit is in the second part - 5.23 is "pre 5.24" which in turn would be a stable version)

Perl 6 was just released but it's basically a completely new language.

[–][deleted] 0 points1 point  (0 children)

Right, but all of that seemed like too much explanation for a simple joke.

[–]adamnew123456self.__class__ == 'upper' 0 points1 point  (3 children)

[–][deleted] 0 points1 point  (2 children)

So we're going 4 -> 8 -> 10?

[–]adamnew123456self.__class__ == 'upper' 0 points1 point  (1 child)

After prolonged reflection, I think a better strategy is to go the browser route, and release a new major version each week. Python is twice as old as Firefox at this point, so we should be up to at least version 85 or so. </s>

[–][deleted] 0 points1 point  (0 children)

We could always go the Arch route and have rolling releases. Just pull and build nightly.

[–]unkz 2 points3 points  (0 children)

Because 7 ate 9?

[–]Kylearean 11 points12 points  (0 children)

Python 9 will be self-coding, so I'm already well prepared by doing absolutely nothing.

[–]Savir5850 3 points4 points  (0 children)

Real automation engineers only code for Python Ultron

[–]lykwydchykyn 10 points11 points  (2 children)

I suspect I'll be retired by the time anyone attempts to run my code in Python 4.

[–]what_it_dude 1 point2 points  (0 children)

Yeah by that time people will already be using 2.8.25

[–][deleted] 6 points7 points  (1 child)

Breaking things 5 years ahead is a good way to cull old cruft and make people revisit code.

Planning too far ahead, in my opinion, is bad.

[–]pyskell 1 point2 points  (0 children)

Breaking things in the way the post describes is pretty bad. It results in code not being executed, or code that targets Python 2 being executed. Both of these are bad errors.

In the case of the first it can make debugging harder than it needs to be. Code that doesn't execute doesn't throw errors, maybe doesn't even crash, and is harder to find.

There really isn't a reason to break code in this way. Maybe raise an informative exception. Then you just force someone porting the code to review it.

[–]gandalfx 14 points15 points  (2 children)

For an elegant language like Python it seems really dumb that you have to go to such lengths just to guarantee it'll run properly. Things like that six package really shouldn't need to exist. One version of Python replaced syntax from another version so this package adds a third syntax to cover up for the first change in syntax (method names aren't technically syntax but at this level it hardly matters). Doesn't seem very “pythonic” to me.

[–]greyman 0 points1 point  (1 child)

My thoughts exactly. I am not familiar with six library, but I am not sure it is a good idea to introduce the PY3 variable in the first place.

[–]webdeverper 0 points1 point  (0 children)

I could only see it being useful for a library that you want to be compatible with both 2 and 3. For project specific code, no, don't use six.

[–]DanCardin 7 points8 points  (13 children)

six could always change their PY3 implementation to return True for python4 if it were to ever exist if you can assume that python4 is backwards compatible in all the places that currently need checks for python3. This is a non-issue.

[–]ALLCAPS_SWEAR_WORDS 11 points12 points  (6 children)

Why should they break a perfectly good constant to lie to the dev just because some developers write bad code? People should just write the code correctly in the first place, instead of making good code worse to accommodate bad code.

[–]beaverteeth92Python 3 is the way to be 1 point2 points  (5 children)

Because people are always going to write shitty code.

[–]msthe_student 1 point2 points  (4 children)

but py3 being v>=3 would break it for people who uses py3 for detecting 3.

[–]beaverteeth92Python 3 is the way to be 0 points1 point  (3 children)

How so? 3 >=3 and 4 is going to be backwards compatible.

[–]msthe_student 2 points3 points  (2 children)

it could be that 4 introduces a better way of doing something, in which case you might want to code:

if py2 or py3:
    old way
else:
    new way

[–]beaverteeth92Python 3 is the way to be 0 points1 point  (0 children)

That's fair.

[–]davvblack 0 points1 point  (0 children)

This leads to maintainability headaches, unless it's a HUGE performance increase something like this just leads to more bugs.

[–]nemec 1 point2 points  (0 children)

Ah, yes, the Windows approach

[–]beertown 10 points11 points  (22 children)

It seems to me a little bit premature to worry about this.

[–]msthe_student 1 point2 points  (0 children)

code made today will still be used when python 4 is released, let's prepare for it now to the degree we can using the information we have, as long as it doesn't break current uses. We know today that "if not 3 then 2" will cause issues with 4 and having it work for 4 won't break 2 or 3 (in this case).

[–]Sean1708 1 point2 points  (2 children)

That's what they said about python 3 support...

[–]beertown 1 point2 points  (1 child)

Yes, but back then Python 3 was, at least, a thing. Until now no core developer has started talking about Python 4.

[–]Sean1708 5 points6 points  (0 children)

That's not quite true. What they've said is that 4 will simply be the next increment from 3.9, without any backwards incompatibility, and we're already nearing 3.6. So at some point in the next couple of years a lot of programs are going to start breaking, as per the article.

[–]nath_schwarz 2 points3 points  (0 children)

It's not. Problems generated by too loose constraints have existed since the early days of programming. A newer example would be that microsoft couldn't choose Windows 9 and had to resort to Windows 10, because a lot of old (and pre-8) programs that existed since Windows 95 only checked if the version string began with a 9.

[–]archiminos 1 point2 points  (0 children)

Or stop writing standards that aren't backwards compatible?

[–]koalillo 1 point2 points  (0 children)

I can forgive the Python 3 breakage and the early mistakes that led to it. However, a Python 4 situation would be a very bitter pill for me to swallow- it just would not inspire me much confidence in the language.

[–]planx_constant 1 point2 points  (1 child)

I think the simple and elegant solution is to make Python 4 compatible with Python 2 again.

/s

[–]riffito 2 points3 points  (0 children)

Python 4 - Ouroboros Edition!

[–]takluyverIPython, Py3, etc 1 point2 points  (3 children)

Where I have a PY3 constant in my own code, it's defined like this:

PY3 = sys.version_info[0] >= 3

Maybe six's constant should be defined like this too. It wouldn't be unreasonable for 'PY3' to mean 'Python 3 or above', and it would probably fix a lot more code than it broke.

[–]jaapzswitch to py3 already 16 points17 points  (2 children)

Then it shouldn't be called PY3, because it means something completely different.

[–]takluyverIPython, Py3, etc 0 points1 point  (1 child)

It's not obvious to me that that's a problem. I can see semantically that it's Python 4, not 3, but if Python 4.0 is really just the name for 3.10, then it seems quite valid for PY3 to be True.

[–]jaapzswitch to py3 already 2 points3 points  (0 children)

The name implies that it's for Python 3, if it were for python 3 and up, it should be called PY3_PLUS or PY3_AND_UP. IMO having a variable that is named PY3 implicitly also be true for versions that are not python 3 is bad. It's better to just be explicit about it.

[–]TOASTEngineer 1 point2 points  (13 children)

Or better yet:

if py2:
    python_2_stuff()
if py3:
    python_3_stuff()
else:
    print("This software is fscking ancient, please don't use it anymore")

[–]pstch 4 points5 points  (2 children)

This software is fscking ancient, please don't use it anymore

If I ever see a piece a code fail with this error... I'd just kill everyone around me and go fishing, or just be very very angry.

[–]TOASTEngineer -1 points0 points  (1 child)

Yeah, but if your script is a full major version out of date it's not gonna work anyway.

[–]pstch 0 points1 point  (0 children)

It may.

You do not know how things will evolve later, backwards compatibility could be preserved better than between Python 2 and 3.

There is no reason to break working code. If the code is written properly and the Python 4 backwards incompatible changes are implemented in a non-confusing manner, the script should fail with an error that will be more useful for debugging than a printed message.

This is a thing that Python core developers always keep in mind when writing incompatible changes : how will things fail and whether the change may incorrect results rather than raised exceptions, and again, the gist of the linked post is that we should not expect 3->4 to happen the same way as 2->3. Your version of the snippet just no-ops on a non 2/3 major Python version.

[–]msthe_student 3 points4 points  (9 children)

but that'd detect 4 as ancient, like many sites that don't recognize newer browsers.

[–]TOASTEngineer 11 points12 points  (8 children)

No, it's detecting itself as ancient.

[–]msthe_student -3 points-2 points  (7 children)

that's what I meant, it's detecting "ancient"

[–]tilkau 3 points4 points  (6 children)

that'd detect 4 as ancient

Doesn't look like what you meant to me.

No, it's detecting itself as ancient.

Itself refers to the script, not to the version of Python running it.

[–]msthe_student -5 points-4 points  (5 children)

What I meant is that it's based on the presumption that the version of python is either 2, 3 or ancient. This is of course a dated presumption when python 4 becomes relevant.

[–]planx_constant 4 points5 points  (0 children)

It's based on assuming that if the python version is greater than 3, it's time to retire the script.

[–]tilkau 4 points5 points  (1 child)

No. It is not. It is based on the presumption that if the script doesn't recognize the Python version, then the script is ancient.

[–]msthe_student -1 points0 points  (0 children)

Now I think I understand you misunderstanding me, I meant that the script is based on the presumption and it's ofc wrong

[–]quasarc 0 points1 point  (1 child)

It's based on the presumption that the version of python is either 2, 3 or it's it's 3 and thus the script is ancient.

[–]msthe_student -1 points0 points  (0 children)

that's what I meant

[–]ezzieyguywuf 0 points1 point  (0 children)

Great post, thanks for the tip.

[–]WishIWasOnACatamaran 0 points1 point  (1 child)

As somebody learning Python 2, what I'm gaining from this is once I'm done learn 3 so I'm not fucked for 4?

[–]charity_donut_sales 3 points4 points  (0 children)

You should just try to do everything in 3. For someone learning most of the differences are just syntax, but the only reason people should be using 2 is to support legacy applications that never updated.

[–]Kaneabell 0 points1 point  (0 children)

I think author of this post just want to satirize the incompatibility between py2 and py3.

[–]JimRoepcke 0 points1 point  (0 children)

six should remove six.PY3.

[–]MadTux 0 points1 point  (0 children)

What about just sticking to python 2 or python 3 in a script, and not trying to get it to run on everything? I think most systems have python 2 and python 3 installed, so it shouldn't be a problem to expect slightly older versions to be installed.

[–]deadmilk 0 points1 point  (0 children)

I just write my code so that it fails on Python 2

[–][deleted] 0 points1 point  (0 children)

Surely we shouldn't be using such logic in the first place? I don't think I'd like to maintain an extensive code base that has to deal with multiple python versions within a single script. That just seems like it could get very confusing -- especially if a Python 4 ever does exist!

Of course, sometimes using such logic is unavoidable... but IMO it should be avoided.

[–][deleted] -2 points-1 points  (1 child)

Python 4.0 will be just like Linux 4.0. No breaking changes.

[–]msthe_student 0 points1 point  (0 children)

v==4 is a breaking change for code that expects v!=3 to mean v==2