Porting from Python 2 Code to Python 3, easy steps.

This tutorial will guide you through best practices and considerations to make when migrating code from Python 2 to Python 3 and whether you should maintain code that is compatible with both versions.

Start with Python 2.7

To move to Python 3, or to support Python 2 and Python 3 simultaneously, you should ensure that your Python 2 code is completely Python 2.7 compatible.

Many developers have already been working exclusively with Python 2.7 code, but it is important to confirm that anything that is only supported by earlier versions is working properly with Python 2.7 and is consistent with Python 2.7 style.

Making sure that your code is in Python 2.7 is especially important because it is the only version of Python 2 that is still being maintained and receiving bugfixes. If you are working on an earlier version of Python 2, you will have to work around issues you encounter with code that is no longer supported and is no longer receiving bugfixes.

Additionally, some tools that make it easier for you to port code, such as the Pylint package that looks for programming errors, is not supported by versions of Python that are earlier than 2.7.

It is important to keep in mind that though Python 2.7 is currently still being supported and maintained, it will eventually meet its end of life. PEP 373 details the Python 2.7 release schedule and, at the time of writing, marks its sunset date as 2020.

Test Coverage

Creating test cases can be an important part of the work done to migrate Python 2 to Python 3 code. If you are maintaining more than one version of Python, you should also ensure that your test suite has good coverage overall to ensure that each version is still working as expected.
As part of your testing, you can add interactive Python cases to the docstrings of all of your functions, methods, classes, and modules and then use the built-in doctest module to verify that they work as shown.

Alongside doctest, you can use the coverage.py package to track unit test coverages. This tool will monitor your program and note which parts of the code have been executed and which parts could have been executed but were not. coverage.py can print out reports to the command line or provide HTML output. It is typically used to measure the effectiveness of tests, showing you what parts of the code are being exercised by testing and which are not.

Keep in mind that you are not aiming for 100% test coverage โ€” you want to make sure that you cover any code that is confusing or unusual. For best practices, you should aim for 80% coverage.

Learn About Differences Between Python 2 and Python 3

Learning about the differences between Python 2 and Python 3 will ensure that you are able to leverage the new features that are available, or will be available, in Python 3.

Our guide on โ€œPython 2 vs Python 3โ€ goes over some of the key differences between the two versions, and you can review the official Python documentation for more detail.

When getting started with porting and migration, there are several syntax changes that you can implement now.

print

The print statement of Python 2 has changed to a print() function in Python 3.

"""Python 2"""
print "Hello World..!!"

"""Python 3"""
print("Hello, World!")

exec

The exec statement of Python 2 has changed to a function that allows explicit locals and globals in Python 3.

"""Python 2"""
exec code
exec code in globals
exec code in (globals, locals)

"""Python 3"""
exec(code)
exec(code, globals)
exec(code, globals, locals)

/ and //

Python 2 does floor division with the / operator, Python 3 introduced // for floor division.

"""Python 2"""
5 / 2 = 2

"""Python 3"""
5 / 2 = 2.5
5 // 2 = 2
exec(code, globals, locals)

To make use of these operators in Python 2, import division from the __future__ module:

from __future__ import division

raise

In Python 3, raising exceptions with arguments requires parentheses, and strings cannot be used as exceptions.

"""python 2"""
raise Exception, args
raise Exception, args, traceback
raise "Error"

"""python 3"""
raise Exception
raise Exception(args)
raise Exception(args).with_traceback(traceback)
raise Exception("Error")

except

In Python 3, raising exceptions with arguments requires parentheses, and strings cannot be used as exceptions.
In Python 2 it was difficult to list multiple exceptions, but that has changed in Python 3.
Note that as is used explicitly with except in Python 3

"""python 2"""
except Exception, variable:

"""python 3"""
except AnException as variable:
except (OneException, TwoException) as variable:

def

In Python 2, functions can take in sequences like tuples or lists. In Python 3, this unpacking has been removed.

"""python 2"""
def function(arg1, (x, y)):

"""python 3"""
def function(arg1, x_y): x, y = x_y

expr

The backtick syntax of Python 2 no longer exists. Use repr() or str.format() in Python 3.

"""python 2"""
x = `355/113`

"""python 3"""
x = repr(355/113):

Conclusion

It is important to keep in mind that as more developer and community attention focuses on Python 3, the language will become more refined and in-line with the evolving needs of programmers, and less support will be given to Python 2.7. If you decide to maintain versions of your code base for both Python 2 and Python 3, you may have increasing difficulty with the former as it will receive fewer bugfixes over time.

 

Amit Baswa

Amit Baswa 1991 born professional web and applications developer with a degree of BSc in Information Technology. He started the blog Pythinks.com to help beginners and seekers in achieving most out of Python programming.