T
T
TODO•SEC
Search…
Python 2 vs Python 3
How to overcome some of the differences between major versions with the use of __future__

print

**In Python 2: **

print is a _statement _
**In Python 3: **
print is a function
Functions need parenthesis around the arguments we're passing them
**In Python 2: **
If we were to wrap our string in parenthesis it would print without issues... But...
It would also 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
It converts it to a string because it is a single object tuple
If we were to add a second object, it would be kept as a tuple after hitting enter
This time the tuple was not transformed to a string
This is not the behavior that would be observed In Python 3 :
In Python 3 print is a function and needs to have arguments passed in ()
Since print is a function in Python 3 , the arguments would be passed to print() function and they would be printed as expected
print is a function in Python 3 and arguments are passed to print()
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 _
First, we import it from __future__:
from __future__ import print_function
print function behaves like in Python 3
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
Just as in Python 3, print"hello", errors out. See below
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.
A floating point number aka "float", is a number that includes decimal portion.
Again, if we wanted to have Python 2 behave like Python 3, we may import the **division __future__ **module
We import division from __future__
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.
we may use double slash '//' and receive the truncated remainder output
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:
we would get a name error saying that "hello" is not defined
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
The value we initialized (242) and assigned to hello is now "x"
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.
This is typically what you want.
In Python 3:
The behavior raw_input would have in Python 2 is default in Python 3
In Python 3: the functions of raw_input are performed by input. raw_input does not exist in Python 3.
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.
Attempt to use raw_input, otherwise, in case of NameError use input()

The following snippet was tested on Python 2.7 and Python 3.8 and demonstrate this concept:

1
from __future__ import absolute_import, division, print_function
2
from pip._vendor.distlib.compat import raw_input
3
4
5
def get_input(prompt=''):
6
try:
7
line = raw_input(prompt)
8
except NameError:
9
x = input(prompt)
10
return line
11
12
13
x = get_input('Type : ')
14
15
print(x)
Copied!
Last modified 8d ago