Project Nayuki


Ending my support for Python 2

Introduction

Python 3 is the current major version of the Python programming language. It brings significant but incompatible improvements and changes compared to Python 2. The transition process in the software development community has painfully taken the better part of a decade, but it has long passed the tipping point.

Over the years, I’ve published many pieces of code in Python – including libraries, test suites, and runnable programs – and will continue to write more Python in the future. At first, my code was designed for and only tested on Python 2. After I started using Python 3, I updated/wrote/tested polyglot code that works on both 2 and 3, to give my users a choice during the transition period. Now, I am permanently moving away from Python 2, effective immediately (April 2020).

Python history

The last time that new features were implemented in the Python 2 lineage was version 2.7 in July 2010. Afterwards, there were infrequent releases for minor bug fixes and security updates, culminating in the last version of 2.7.18 in April 2020. The organization declared that all activity in the Python 2 line stops in Jan 2020. Although third parties are allowed to continue supporting and updating Python 2, they are not allowed to brand it as Python. These factors ensure that Python 2 is a dead end whose utility only diminishes with time.

The Python 3 series first appeared as version 3.0 in Dec 2008. It was somewhat rough at first, but got better over the years. An important milestone is that in version 3.3 (Sep 2012), string literals can be prefixed with u, which dramatically eases polyglot code that must work in both 2 and 3. Besides that, the language syntax and standard library grew more useful features with each minor version release in the 3 line, but never to be backported to the 2 line. Many other people have written a great deal about the differences between Python 2 and 3, so I will only highlight a few points that matter to me personally.

Personal history

I first learned Python 2 in my first year of university in 2007, and used it occasionally for jobs and personal projects (while my major language was still Java). Even as Python 3 emerged into the world, I paid little attention due to personal inertia and not seeing vocal advocacy from authors on the web. It didn’t help that I worked in a job from 2012 to 2014 which used a Python 2.6/2.7 environment.

Digging through my code history, in 2013 I changed about ten Python source code files that were published on this website to become 2-and-3 compatible. From that point forward, all new code I published would also be polyglot. In 2014, I started labeling some of my private standalone scripts as targeting only Python 2 and explicitly not 3. In 2015, the personal scripts that I wrote or edited had become only for 3; furthermore, my commitment to the transition was sealed when I upgraded this website’s server-side application code to be 3-only.

In 2013 when I converted my existing published Python code, that collection was rather small compared to what I offered in Java and JavaScript. The vast majority of my Python work available today was created after that point; for example, I added Python to my Project Euler solutions in 2015. This explains why it was surprisingly painless to upgrade all my published code.

My changes

You must assume that all my currently available published code only supports Python 3 and never assume that it works correctly in Python 2. If you run my code at your own peril in a Python 2.x interpreter, any of these outcomes are possible: Behaving correctly, crashing cleanly, corrupting data or giving wrong answers, or being subtly broken in some obscure edge case.

Although I won’t accept requests for support, you are free to look at old versions of my code that supported both Python 2 and 3. For files published directly on this website, see the repository Nayuki web published code. For files in their own project (e.g. QR Code generator library), see the version history of that particular project.

Now, I write Python code with only version 3 in mind and totally ignore compatibility with version 2 (any such would only be accidental). I will stop my previous practice of testing code in Python 2 to assure compatibility. And I will make these simplifications and changes to my existing code, which require features only available in Python 3 (thus breaking compatibility with 2):

  • Remove the u prefix from text strings.

  • Use f-strings (3.6+) instead of str.format() (2.6+, 3.0+) for building strings from variable parts.

  • Rely on print() being a function. Although print(x) behaves the same on both 2 and 3, essentially all other variations behave differently: print(), print(x,), print(y, z), print(abc, sep="\t", end="", file=qrst), etc.

  • Simplify class Foo(object): to class Foo:.

  • Remove logic that probes for Python 2 (e.g. if sys.version_info.major == 2) and adjusts modules/functions/behavior based on it.

  • Assume that iterator manipulation functions are lazy. For example, range(), map(), and filter() return a full list in Python 2, but they return a generator or iterator in Python 3.

  • Rely on (int / int) yielding a float instead of an int.

  • Forget about the existence of and special cases involving the long integer type.

  • Add optional type annotations to some pieces of code.

  • Forget about the old names of libraries that got renamed, such as the queue and urllib.request modules.

  • Make use of new libraries and members such as pathlib, re.fullmatch(), subprocess.run().

These changes more or less bring my published code in alignment with the standards of my non-published code. In the private realm, I’ve been using purely Python 3 since year 2015, and I don’t hesitate to use library features from the latest or second latest minor version to keep my code concise.

More info