HomeSoftwareDevelopersSupport for Python 2 ends in 2019, and it's high time for...

Support for Python 2 ends in 2019, and it’s high time for developers to take action

Published on

After a long time, the time has come: The support of Python 2 is discontinued. On December 3, 2008, Python 3 saw the light of day. The coexistence of the incompatible versions of Python 2 and Python 3 existed for a good ten years. This unfortunate intermediate state is coming to an end: As announced in 2015, support for Python 2 ends on December 31, 2019.

Python 2 or Python 3, that’s the question

The years of dual support for both versions of Python raises the question of which strategies have evolved to deal with the intermediate state. In short, all conceivable strategies were used. Many simply continued existing projects in Python 2. Some developers even started new projects in Python 2. There were many reasons for this: On the one hand they spoke fluently Python 2, on the other hand necessary libraries were not yet ported to Python 3. Additionally, customers have requested Python 2 code. Some teams just split the codebase in Python 2 and Python 3 and had to maintain both versions.

Although Python 2 and Python 3 are incompatible, it is possible to rewrite Python code to work with both Python 2 and Python 3. The scripts futurize and modernize help with this step . The latter is more conservative than the former when changing the Python code. For the modification, projects must have two prerequisites: a test coverage and code that has been migrated to Python 2.7.

The Cheat Sheet “Writing Python 2-3 compatible code ” cheat sheet describes in detail what syntactical differences exist between Python 2 and Python 3 and how to write Python code that both Python 2 and Python 3 support.

Migration from Python 2 to Python 3

Porting Python 2 code to Python 3 has a well-defined path (see Figure 1), with developers having to test code and troubleshoot every step of the way.

Migration from Python 2 to Python 3 Figure 1
Migration from Python 2 to Python 3 Figure 1

The following lines of code serve as an example for the migration from Python 2 to 3. All lines in the example use Python functional components because some changes have occurred in these built-in functions.

print "sum of the integers:", 
  apply (lambda a, b, c: a + b + c, (2, 3, 4)) 

print "factorial of 10:", 
  reduce (lambda x, y: x * y , range (1,1 1)) 

print "titles in text:", filter (lambda word: word.istitle (), 
                                  "This is a long Test" .split ()) 

print "titles in text:", 
[word for word in "This is a long test" .split () 
  if word.istitle ()]

The first function calculates the sum of the three numbers 2, 3, and 4 by applying the arguments to the lambda function. The built-in reduce () function gradually reduces the list of all numbers from 1 through 10 inclusive by multiplying the result of the last multiplication by the next number from the sequence. The last two functions filter out of the string all words starting with a capital letter. The code already works under Python 2.6, so only steps 3 and 4 have to be done for porting.

Calling the Python 2.7 interpreter with option -3 shows the incompatibilities with version 3 (see Figure 2): Both apply () and reduce () are no longer built-in functions in Python 3.

Figure 2

The code is quickly repaired to avoid deprecation warnings:

print "sum of the integers:", 
  (lambda a, b, c: a + b + c) (* (2, 3, 4)) 

import functools 

print "factorial of 10:", 
  functools.reduce (lambda x, y: x * y, range (1, 11)) 

print "titles in text:", 
  filter (lambda word: word.istitle (), 
          "This is a long Test" .split ()) 

print "titles in text: ", 
  [word for word in this is a long test" .plit () 
   if word.istitle ()]

The 2to3.py script (see Figure 3) proves useful when correcting the Python 2 code because it automatically generates code for Python 3 in the last step.

The direct way is to override the source file : python <path to 2to3.py> port.py -w . The result is the source code ported to Python 3. Interestingly, the code generator has replaced the filter ()expression with an equivalent list comprehension:

print ("sum of the integers:", 
  (lambda a, b, c: a + b + c) (* (2,3,4))) 

import functools 

print ("factorial of 10:", 
  functools.reduce ( lambda x, y: x * y, list (range (1,11)))) 

print ("titles in text:", 
  [word for word in "This is a long Test" .split () 
   if word.istitle () )]) 

print ("titles in text:", 
  [word for word in "This is a long Test" .split () 
   if word.istitle ()])

Python 3: The new features

Of course, the migration from Python 2 to Python 3 has pitfalls and weaknesses. As part of the porting developers should familiarize themselves with the new features of Python 3.

print is a function with Python 3. The new syntax is generally the following:

print (* args, sep = "", 
      end = "\ n", 
      file = sys.stdout, 
      flush = true)

Where args denotes the arguments, sep the separator between them, end the end-of-line character, file the output medium and flush the buffer. The following table compares the syntactic changes to the print function, including their default values.

The following table shows the differences for print in Python 2 and Python 3:

example Python 2.x Python 3.x
General form print “x =”, 5 print (“x =”, 5)
wordwrap print print ()
Subdue the line break print x, print (x, end = “”)
Suppress the line break without spaces   print (1, 2, 3, 4, 5, sep = “”)
Redirection of the output print >> sys.stderr, “error” print (“error”, file = sys.stderr)

The advantage of the new version reveals itself only at second glance, because the printfunction is now overloaded: The listing shows a print function that writes both in the standard output as well as in a log file. For this purpose, it exploits the built-in function __builtins __. Print .

import sys 

def print (* args, sep = "", end = "\ n", 
          file = sys.stdout, flush = True): 
  __builtins __. print (* args, sep = sep, end = end, 
                     file = file, flush = flush) 
  __builtins __. print (* args, sep = sep, end = end, 
                     file = open ("log.txt", "a"))

The biggest difference between Python 2 and Python 3 can be found in the strings. If programmers in Python had to explicitly declare 2 strings as Unicode ( u “unicode string” ), strings in Python 3 automatically consist of Unicode characters ( “unicode string” ). Python 3 knows text and (binary) data instead of Unicode strings and 8-bit strings. Binary data in Python 3 is explicitly defined by “binary data” . Text is Unicode, while encoded Unicode stands for binary data. The data type that contains text is “str” , the data type that contains data is “bytes”.

The exact details about strings in Python 2 and Python 3 can be found in the Unicode How-to.

To convert data types, the functions str.encode () and bytes.decode () exist. The transformers will need developers in Python 3 if they use both types of data because there is no implicit type conversion.

With so-called Function Annotations, the metadata in Python 3 can be bound to a function. In the second step , the latter can also be provided with decorators, which automatically generate documentation from the metadata or check the types at runtime. The equivalent functions sumOrig () and sumMeta () show the function declaration with and without metadata. The latter can be found in the second function for the signature and the return value. The metadata can be referenced using the function attribute __annotations__.

Necessary cleanup

Not only does Python 3 bring new features, it also cleans up Python 2 altogether. The adjustments affect libraries that

  • were removed
  • be written in lowercase according to the Python Style Guide,
  • newly packed in packages or
  • coexist in a C and Python implementation.

The well-known Python idiom of importing the fast C implementation of a module and using the Python implementation in case of an error is no longer necessary. Python takes care of it automatically.

try: 
    import cPickle as pickle 
except ImportError: 
    import pickle

More details on the changes to the standard library can be found in an overview of the new features.

There are other things that make writing code in Python 3 easier. For co-operative super calls, developers no longer have to name the instance of the class and the class name. Python 3 only knows New Style classes, so the annoying deriving of object is no longer necessary to address the newer features of Python.

The automatic evaluation of the input with the input ()command is superfluous, as the input in Python 3 is available as a string. This has closed a big security hole in Python. Consequently, raw_input () is now called input () .

The purpose of Python 2.7 is to simplify the transition to version 3. Therefore, the project has backported many features from Python 3.0 to Python 2.7.

Backports on Python 2

The Context Manager with with is an important new feature available with Python 2.6. A resource such as a file, socket, or mutex automatically binds Python when it enters the withblock and releases it when it exits. C ++ programmers may remember the idiom of Resource Acquisition Is Initialization (RAII).

The with statement behaves from a user perspective as a try … finally , since both the tryblock and the finally block always be executed. However, this happens without explicit exception handling.

In a with block you can use any object that offers the context management protocol and thus has the internal methods __enter () __ and __exit () __ . When entering the with block, Python calls __enter () __ – and exits _exit () __ method. The file object brings with it the appropriate methods.

Resource management can also be implemented by hand using the methods __enter () __and __exit () __ . If manual writing is too much work, you can use the decorator contextmanager from the contextlib library to benefit from context management. Further use cases can be found in the Python Enhancement Proposal (PEP) 0343.

with open ('/ etc / passwd', 'r') as file: 
    for line in file: 
    print line, 
# file is automatically closed

Probably the largest syntactic extension takes place in Python 2.6 with the introduction of abstract base classes. Whether an object can be used in a context depends on the characteristics of the object and not on its formal interface specification.

The idiom is called Duck-Typing – free after the poem by James Whitcomb Riley: “When I see a bird that walks like a duck and swims like a duck and quacks like a duck, I call that bird a duck”.

Once a class has an abstract method, it becomes an abstract base class and can not be instantiated. Derived classes can only be generated if they implement the abstract methods. Abstract base classes in Python behave similarly to in C ++, in particular, abstract methods may contain an implementation.

In addition, Python also knows abstract properties. Python 3 uses abstract base classes in the numbers and collections modules.

The answer to the question still arises as to how a class becomes an abstract class: it needs the metaclass ABCMeta . Then the methods can be declared as @abstractmethod or properties as @abstractproperty with the respective decorators. The use of abstract base classes also means that the static typing feeds into the dynamically typed language.

Parallel work

Python’s answer to multiprocessor architectures is the new multiprocessing library. It imitates the well-known Python module threading , but instead of a thread creates a process – platform independent. The multiprocessing module was necessary because in the standard implementation CPython only one thread can run in the interpreter. The behavior is due to the so-called Global Interpreter Lock (GIL).

Conclusion

The Python community has described workflows and provided tools to greatly simplify the transition from Python 2 to Python 3. The typical migration strategy should begin with a test coverage, as summarized in Figure 1, and end with automatic code migration, using the 2to3 tool.

Anyone planning and consistently implementing the migration strategy throughout the year should not encounter any obstacles in the process of migrating from Python 2 to Python 3. As of 2020, Python 2 is history and only Python 3 is allowed.

Latest articles

Here’s How and When Mount Everest-sized ‘Devil Comet’ Can Be Seen With Naked Eye

Mount Everest sized Comet 12P/Pons-Brooks, also known as "devil comet" which is making its...

Something Fascinating Happened When a Giant Quantum Vortex was Created in Superfluid Helium

Scientists created a giant swirling vortex within superfluid helium that is chilled to the...

The Science of Middle-aged Brain and the Best Thing You Can Do to Keep it Healthy, Revealed

Middle age: It is an important period in brain aging, characterized by unique biological...

Science Shock: Salmon’s Food Choices Better at Reducing Risk of Heart Disease and Stroke

Salmon: Rich in Health Benefits, Yet May Offer Less Nutritional Value - This is...

More like this

Here’s How and When Mount Everest-sized ‘Devil Comet’ Can Be Seen With Naked Eye

Mount Everest sized Comet 12P/Pons-Brooks, also known as "devil comet" which is making its...

Something Fascinating Happened When a Giant Quantum Vortex was Created in Superfluid Helium

Scientists created a giant swirling vortex within superfluid helium that is chilled to the...

The Science of Middle-aged Brain and the Best Thing You Can Do to Keep it Healthy, Revealed

Middle age: It is an important period in brain aging, characterized by unique biological...