Python 2 vs Python 3
How to overcome some of the differences between major versions with the use of __future__
Introduction Video to the full series
print
**In Python 2: **
print is a _statement _
**In Python 3: **
print is a function
**In Python 2: **
If we were to wrap our string in parenthesis it would print without issues... But...
Why?
Because 'hello' in Python 2 would be a **tuple **of a single object .
What is a tuple?
Collection or two (2) or more objects. Tuples are represented by using parenthesis around the objects that comprise them .
**In Python 2: **will just convert this back to a string
If we were to add a second object, it would be kept as a tuple after hitting enter
This is not the behavior that would be observed In Python 3 :
Since print is a function in Python 3 , the arguments would be passed to print() function and they would be printed as expected
If we want our scripts to run in Python 2 and in Python 3 , we would want _common operations _such as print to run in both versions.
How to write Python scripts that run on Python 2 and Python 3?
Importing futures
A solution to the problem stated above is given by the use of futures. "futures" make Python 2 behave like Python 3 for certain functions.
feature | optional in | mandatory | effect |
---|---|---|---|
nested_scopes | 2.1.0b1 | 2.2 | PEP 227: Statically Nested Scopes |
generators | 2.2.0a1 | 2.3 | PEP 255: Simple Generators |
division | 2.2.0a2 | 3.0 | PEP 238: Changing the Division Operator |
absolute_import | 2.5.0a1 | 3.0 | PEP 328: Imports: Multi-Line and Absolute/Relative |
with_statement | 2.5.0a1 | 2.6 | PEP 343: The “with” Statement |
print_function | 2.6.0a2 | 3.0 | PEP 3105: Make print a function |
unicode_literals | 2.6.0a2 | 3.0 | PEP 3112: Bytes literals in Python 3000 |
generator_stop | 3.5.0b1 | 3.7 | PEP 479: StopIteration handling inside generators |
annotations | 3.7.0b1 | 4.0 | PEP 563: Postponed evaluation of annotations |
In this case _**print **is _
print_function:
First, we import it from __future__:
from __future__ import print_function
Now if after importing print_function from __future__ we attempted to use the print function, it will never behave like a statement again which is the native Python 2 behavior
In Python 3: if we were to import print_function from __future__
_from __future__ import print_function _it would just ignore it.
Nothing changes in the behavior of Python 3 by importing the print function from __future__
Division
In Python 2, floor division drops the remainder and returns only a whole number.
Python 2 thinks that you are dividing an integer by an integer, and that you probably want and integer back and drops the remainder.
If, instead, we were to provide one of the numbers as a float, the returned result would be a float too.
Again, if we wanted to have Python 2 behave like Python 3, we may import the **division __future__ **module
After importing the **division module from __future__ **and performing a division that would yield a remainder we can observe that **Python 2 **is outputting the expected remainder
Additionally, we can observe that if we escape the / (backslash) we may receive the output without the remainder again.
Why would we want to do this? Convenience, sometimes you would want to get one output or the other
To provide our Python 2 scripts with some forward compatibility, we may use the following line in our scripts:
from __future__ import absolute_import, division, print_function
Input Function
If I wanted to get input from an user, assigning it to variable X:
We may prompt the user to type something:
The error is letting us know that that python does not have any objects named "hello"
If now, in contrast we do create an object called hello and assign it the value 242
This time we get no error because hello has been previously defined
It would not be uncommon to think that x = hello right?
No. Why? Because it assigned to X the value of the hello object we had previously created
As you can imagine this behavior is not useful.
raw_input function
The raw_input function helps us in this case. Fixes the issue because using raw input, when I type something
and I check the value of x, it is being assigned to what I typed.
In Python 3:
In Python 3: the functions of raw_input are performed by input. raw_input does not exist in Python 3.
How to run a script that works consistently on both versions
We may leverage the fact that raw_input creates an error in python 3 and we can tell it to try raw input and catch the exception and NameError, use input function instead.
The following snippet was tested on Python 2.7 and Python 3.8 and demonstrate this concept:
Last updated