Python 2 vs Python 3

How to overcome some of the differences between major versions with the use of __future__

Full Source video

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.

featureoptional inmandatoryeffect

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

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:

from __future__ import absolute_import, division, print_function
from pip._vendor.distlib.compat import raw_input


def get_input(prompt=''):
    try:
        line = raw_input(prompt)
    except NameError:
        x = input(prompt)
    return line


x = get_input('Type : ')

print(x)

Full Source video

Introduction Video to the full series

Last updated