Reputation: 27403
I'm not interested in warming up the "Python 2 or Python 3?" questions (even though the most recent one I found is over one year old), but I stumbled upon this claim:
You can write the Python 3 code under Python 2 if your file begins with the line:
from __future__ import absolute_import, division, generators, unicode_literals, print_function, nested_scopes, with_statement
With that line in place, your code will work with either Python 2 or Python 3. There may be rare cases in which it doesn't work, but I have not found any,
Is this true? Is this single line enough to make sure the code you write will run on both Python 2.x (>=2.5 I assume) and 3.x (assuming the modules imported are available in both)?
Upvotes: 12
Views: 5494
Reputation: 449
You can use the future package: pip install future
In [1]: range(10)
Out[1]: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
In [2]: from future.builtins import range
In [3]: range(10)
Out[3]: range(0, 10)
Here is their cheat sheet with more examples: http://python-future.org/compatible_idioms.html
Upvotes: 1
Reputation: 184211
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...
Upvotes: 8
Reputation: 172249
"It depends"
No: Adding these imports to your Python 2 code will not make it run under Python 3.
Yes: With these imports in place you can write code that runs under both Python 2 and Python 3.
But: Then again, you can do that without those imports as well, and several of them, such as unicode_literals
have turned out to simply not be helpful. generators
and with_statement
have nothing to do with Python 2 to Python 3 at all, those are features added in versions of Python 2.
So in conclusion, these imports are a bit of a red herring, and the statement is more wrong than right.
However, that doesn't mean writing code that runs under both Python 2 and Python 3 is impossible, or even necessarily very hard. See http://python3porting.com/ for more info.
Upvotes: 7
Reputation: 44364
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....
Upvotes: 3
Reputation: 157364
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.
Upvotes: 5
Reputation: 89017
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.
Upvotes: 4