Porting Python 2 to Python 3
The world is changing rapidly and python’s too. At the beginning of this unfortunate year 2020, Python Software Foundation announced “January 1, 2020, was the day that we sunset Python 2”. Nobody likes these drastic changes, especially if you're a Python developer. But it’s not a sudden change, Python Software Foundation was thinking about these major changes since python 2.6 was released and they have been adding tools which will help you to port from Python 2 to Python 3 since then, which we will discuss in this blog later.
For migrating from python 2 to python 3, you must have prior knowledge of what are the key changes introduced and how they will impact your application.In the first section, we’ll introduce the major changes in python 3 and the benefits they will give. So consider this section as primer and motivation for migrating to Python 3.
Python 2 vs Python 3
In Python 2, 5/2 is evaluated as 2. Yes, Python 2 is infamous for casting the result of integer division into integer, due to which developers have to use float variables for getting correct results. But now in Python 3, 5/2 is evaluated as 2.5. All division between int will result in a float result.
Text vs Binary Data
Previously in Python 2, you could use the str type for both text and binary data. This leads to many confusion and bugs due to indistinction of 2 completely different concepts in Python. Therefore, in Python 3, it uses unicode type by default for saving textual data, so you don’t have to explicitly convert text data to unicode type by passing data to the constructor everytime. In simple words, Python 2 is handling textual and binary data as unicode string and 8-bit string respectively, and now in Python 3, treat both of them as 2 different things text and (binary) data.
Now let’s discuss the most tricky part that is making your Python 2 code to support the new distinction between text and binary data. If your code doesn’t use binary and textual data, you are good to go, but if you use them together for eg. comparing binary string with unicode string, your code is doom and needs to fix immediately. So first of all use bytes and unicode constructor for getting distinction between binary and textual data in Python 2 code too. Then if you are comparing binary and textual data, then use encode() and decode() for converting unicode string to binary string and vice versa respectively.
This change is more of a syntactic change than that of a semantic change and will not impact your python application, but it’s a major change and more visible change. In python 2, print statement is an operator and is used like print “Hello World!”. But in Python 3, print is a function and is used as print(“Hello World!”).
In Python 3, iteritems is replaced by items method. Also dictionary method like keys, values, etc, including items return a copy of the dictionary’s list of (key, value) pairs, so the return value will not have methods of list. You will have to explicitly convert the return value to list if you are treating it as list in your python 2 code.
map() & filter()
Similar changes like dictionary methods are done with map() & filter(), they are now returning an iterator instead of list. PSF suggested to replace map & filter with list comprehension or pass the result from them to the list constructor to get a list object.
range() behaves like xrange()
In python 3, range() function behaves like xrange() of python 2. The difference is that range returns a list whereas xrange returns an iterator.
Now You know everything you should know before migrating your code to Python 3. Generally migrating from Python 2 to Python 3 will take a week for changes in code and a month for testing and fixing the bugs.
So the best strategy for migrating your code from python 2 to python 3 is to make it supportable for both Python 2/3 and doing changes for migrating gradually piece by piece(or module by module). So I am going to mention resources at your help for this.
Using __future__ module
PSF has introduced this module since the earlier versions of Python 2 by keeping thought of this scenario in mind and encouraged the community to use them so that their Python 2 can be easily ported to the Python 3.
Following is the use for using the Python 3 division functionality in your python code.
Another example of using __future__ module is demonstrated in the following image.
Use Python tools for upgrading your code
There are tools like modernize, futurize, 2to3,etc. which use the Python parser library to translate your Python 2 code to Python 3. But these tools are not fault proof and I don’t suggest you to completely rely on these tools, but it’s nice to have these tools for your reference, so use them responsibly.
Change your code manually
As we have knowledge of what has been changed from Python 2 to Python 3, we can use it to change our code to support Python 3. For example, we know that dictionary methods are now returning an iterator instead of a list, so we can pass that iterator to the list constructor. Similarly we can start using xrange instead of range in your python 2 code, so that when you have to finally move to Python 3, you can simply replace xrange with range in your code.Similarly, You need to wrap map() & filter() to list constructor or use list comprehension instead of them.
With all of these new features in Python 3 and no longer support for Python 2, we highly recommend you to port your application in Python 2 to Python 3 immediately and if the security is the big concern for your application, genuinely stop using outdated Python 2 code, which will not have fixes for the major security threats and attacks.