The Python Oracle

Can a from __future__ import ... guarantee Python 2 and 3 compatibility?

--------------------------------------------------
Hire the world's top talent on demand or became one of them at Toptal: https://topt.al/25cXVn
--------------------------------------------------

Music by Eric Matyas
https://www.soundimage.org
Track title: Puzzle Game 3 Looping

--

Chapters
00:00 Can A From __future__ Import ... Guarantee Python 2 And 3 Compatibility?
00:51 Answer 1 Score 4
02:00 Answer 2 Score 8
03:21 Answer 3 Score 5
03:39 Answer 4 Score 3
04:25 Thank you

--

Full question
https://stackoverflow.com/questions/1110...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #python3x #python2x

#avk47



ANSWER 1

Score 8


I would say that no, this is baloney. Even with those imports, there are still significant differences between Python 2 and 3: for example, input() in Python 3 is like raw_input() in Python 2; range() in Python 3 is like xrange() in Python 2. In the case of xrange() you could probably get away with using range() in Python 2 as long as the ranges are small, but if they're large, your program could have very different memory usage under Python 2 and Python 3.

You could add something like this to your code:

try:
    range = xrange
    input = raw_input
except NameError:
    pass

But then you've got to find all those edge cases and fix them up. For example, there are the keys() and values() methods of dict that return iterators in Python 3 but lists in Python 2, so you'd need to write a dict subclass that "fixes" that (and then never use dictionary literals in your code without wrapping them, since those would otherwise be of the built-in dict type).

I suppose that, by using __future__ and various fix-ups, and by limiting yourself to writing code in a subset of Python thus created that will run under both 2.x and 3.x, it might be possible to write code that runs in both versions. Seems like a lot of work, though. There's a reason there's a 2to3 utility...




ANSWER 2

Score 5


It's not impossible, depending on the demands of your codebase. You will probably find the six (2 * 3, haha) library essential; another useful tool is python-modernize which attempts to convert your code to a cross-compatible state.




ANSWER 3

Score 4


It will make it more likely, but there are some things that cannot be gained from a __future__ import, and some things that are removed going into 3.x.

Off the top of my head, you could still use parameter tuple unpacking, which is removed in 3.x, and you won't be able to use the nice tuple unpacking with the star operator that is introduced in 3.x.

E.g:

def some_function((x, y), magnitude): #This has been removed in 3.x
    pass

x, *y = (1, 2, 3) #This does not exist in 2.x

That said, with some care to avoid such things, you could definitely write code that works across both versions, yes.

Obviously, this also only applies to 2.x versions that have the features backported into them. Because of this, some of that line is actually completely pointless - for example, there is no reason to import generators as any version that can import the with statement will already have generators working as standard. Same goes for nested_scopes.

In general, I recommend just writing for 3.x - there are no barriers to having both versions installed and usable. If you really desperately need 2.x support, then write for 2.x with as many of the back-ported features as you want, and use 2to3 to clean up anything else.




ANSWER 4

Score 3


Nah. Others have pointed out some difference, there are others. One of the most fundamental is that Python 3 native strings are multibyte - this raises issues when communicating with single-byte mechanisms, like pipes to other processes. Others include the renaming of modules (Tkinter to tkinter), True and False are now keywords.

Even comparisons might not be the same, the following incorrect code:

num = 42
txt = "3"

if txt < num:
    print ('Wow!')
else:
    print ('Doh!')

produces a TypeError on Py3, but not on Py2.

Unpacking has been mentioned. the dictionary methods items(), keys(), and values() return view objects (different method names are used on 2.7). In Py3 iterators are used more, for example returned from map() and filter(), and so on....