# Python 2 vs 3

## Summary


Python 3 was released to fix problems present in Python 2. The nature of these changes meant that Python 3 was incompatible with Python 2. It also meant that Python 3 did not carry forward the problems of Python 2. Some aspects of Python 3 have been backported to Python 2.6 and 2.7 to make the migration to Python 3 easier.

Python 2 was supposed to be retired in 2015 but slow adoption of Python 3 led to an extended deadline of 2020. Python 2.7 will receive updates till 2020 for security and bug fixes only. 

As of February 2018, it's seen on Python 3 Readiness that 348 of 360 most downloaded packages from PyPI already support Python 3. 

It's expected that if ever there should be a Python 4, it will be compatible with Python 3.

## Discussion

### What were the main issues with Python 2?

A `str` object could represent either text or binary data. This easily results in bugs because developers often don't use `unicode` type for text. Python 3 solves this by making all `str` Unicode and having `bytes` type to handle binary data. It's explicit and unambiguous. To support string literals involving non-ASCII characters, making Unicode as default is a good thing. 

When functions are treated as objects in Python and can take arguments, `print` is an unnecessary exception. It's a statement in Python 2 but making it a function would be make it more flexible. 

Division that should result in a `float` instead does truncation and results in an `int`. Python 2 needed extra functions/methods to minimize RAM usage but Python 3 does lazy evaluation by default. Although Python is strongly typed, Python 2 permits strange comparisons: `None < 3 < "2"`. 

Nick Coghlan provides a detailed discussion of why Python 3 was defined in a backwards incompatible manner. 


### I am new to Python. Should I learn Python 2 or Python 3?

Python 3 fixes many of the problems that are present in Python 2. Python 3 is also the future of the language since Python 2 will be retired in 2020. It's therefore recommended that beginners learn Python 3. Moreover, if you're going to write new code, Python 3 is the one to choose. Eevee's blog article gives a detailed explanation of all the good things in Python 3. 

If you've to maintain legacy Python 2 code, it's still best to learn Python the right way from Python 3. Then you can study the differences between Python 2 and 3. The point is that the two versions are much more similar than different. 


### What features of Python 3 have been backported to Python 2.7?

Backporting has been done mainly to aid in the eventual migration of Python 2 code to Python 3. A list of backports is documented in the official Python Docs and explained briefly in Eevee's blog.

As an example, `bytes` and `bytearray` are part of Python 3.x but they were backported to 2.6 but with very different semantics. In Python 2, `bytes` is really an alias of `str`. The purpose was really to aid converters such as `2to3`. 


### What are the differences between Python 2 and Python 3 for data types?

Following is a summary of key differences: 


| Python 2.X | Python 3.X |
| --- | --- |
| There's ASCII `str` type and `unicode` type, but no separate type to handle bytes of data | All strings (`str`) are Unicode strings; two byte classes are introduced: `bytes` and `bytearray` |
| Two types of integers: C-based integers (`int`) and Python long integer (`long`) | All integers are long but referred to by the `int` type |
| Return type of division is int if operands are integers: `5 / 4` gives `1`; `4 / 2` gives `2` | Return type of division is `float` even if operands or result are integers: `5 / 4` gives `1.25`; `4 / 2` gives `2.0` |
| `round(16.5)` returns a `float` of value 16.0 | `round(16.5)` returns an `int` of value 16 |
| Unorderable types can be compared | Comparison of unorderable types raises a TypeError |


### What are the other differences between Python 2 and Python 3?

Following is a summary of key differences: 


| Python 2.X | Python 3.X |
| --- | --- |
| `print` is a statement: `print "Hello World!"` | `print()` is a built-in function: `print("Hello World!")` |
| `range()` returns a list of numbers while `xrange()` returns an object for lazy evaluation | `range()` returns an object for lazy evaluation similar to Python 2 `xrange()`; and `range()` method `&lowbar;&lowbar;contains&lowbar;&lowbar;` speeds up lookups |
| Functions/methods `map()`, `filter()`, `zip()`, `dict.items()`, `dict.keys()`, `dict.values()` return lists | These function/methods return objects for lazy evaluation |
| `raw_input()` returns input as `str` and `input()` evaluates the input as a Python expression | `input()` will return a string similar to Python 2 `raw_input()` |
| Raising exceptions: `raise IOError("file error")` or `raise IOError, "file error"` | Raising exceptions: `raise IOError("file error")` |
| Handling exceptions: `except NameError, err:` or `except (TypeError, NameError), err:` | Handling exceptions: `except NameError as err` or `except (TypeError, NameError) as err` |
| On generators, a method or function call: `g.next()` or `next(g)` | On generators, only a function call: `next(g)` |
| Loop variables in a comprehension leak to global namespace | Loop variables are limited in scope to the comprehension |


### What does the Python standard library provide to manage the incompatibility between Python 2 and 3?

The following are some modules that we can use:

    + `builtins`: To create wrappers around built-in functions, `builtins` is useful.
    + `future_builtins`: Function `map` and `filter` in Python 2 behave differently than in Python 3. To get Python 3 behaviour, use `from future_builtins import map, filter`.
    + `&lowbar;&lowbar;future&lowbar;&lowbar;`: In Python 2, to use `print()` only as a function, use `from &lowbar;&lowbar;future&lowbar;&lowbar; import print_function`.
    + `2to3`: To convert Python 2 code to Python 3, this standard library can be used. It applies a series a fixers to do the conversion. It's based on `lib2to3` library, which can be used to add custom fixers. Python Converter is online conversion tool based on `2to3`.

### I have a legacy Python 2 codebase but would like to start supporting Python 3 as well. What can I do?

There are a few approaches that developers can take depending on the need:

    + `modernize`: This is useful when you want to partially support both 2 and 3 with the goal of eventually porting to Python 3.
    + `future`: This enables either Python 2 or 3 code to be used across both versions. It comes with scripts `futurize` and `pasteurize` for 2-to-3 and 3-to-2 conversions respectively so that a single codebase can be used. It's supported for versions 2.6+ and 3.3+. There is a cheatsheet that gives examples of writing compatible code.
    + `six`: This wraps over the differences between 2 and 3 without modifying code. This means the code can run on both versions.It's recommended to drop support for Python 2.6 and older if possible. If legacy code must be maintained, one can opt for commercial services such as from ActiveState. 

Tools such as pylint, caniusepython3 and tox can help in checking or maintaining compatibility. Developers can also refer to a cheatsheet on writing compatible code; or get familiar with common migration problems.

## Milestones

Oct  
2008

Python 2.6 is released. The development of this release is synchronized with that of Python 3.0. Thus, Python 2.6 incorporates some changes that are part of Python 3.0. This backporting is expected to make way for easier migration of Python 2.6+ code to Python 3.x. Module `future_builtins` has 3.0 semantics. 

Dec  
2008

Python 3.0 is released. It simplifies some of the unwieldy syntax that was in Python 2.x. It's not backward compatible with Python 2.x and hence it's release is seen as controversial. However, Python 3.x is the future of the language. Python 3.0 itself is deemed a failure due to slow IO. 

Jun  
2009

Python 3.1 is released and it supercedes Python 3.0 that was unusable. 

Jul  
2010

Python 2.7 is released. It includes some features introduced in Python 3.1. Python 2.7.x releases will receive bug fixes as well as backports from Python 3.x to make it easier in future to migrate that code to Python 3. It's the last 2.x release (there won't be a 2.8 release). It's expected to be retired in April 2020, implying that it will be maintained for 10 years since it's initial release.

Feb  
2011

Python 3.2 is released. A year later, it's seen that with this release Python 3 gains traction. 

Sep  
2012

Python 3.3 reinstates the redundant syntax for Unicode string: `u'hello'`. This is done to enable easier migration from 2 to 3. 

2013

Python 2.6 reaches end of life and at least one expert recommends (in 2016) that developers should move to 2.7 if moving to 3.x is not an option. 

2016

Jake VanderPlas states that the scientific community should adopt Python 3 thanks to tools such as `six` and `future`. In 2013, VanderPlas had noted that moving to Python 3 was impossible (back then). In November, popular Python author Zed Shaw publishes a scathing article against Python 3. A day later, blogger named Eevee publishes a detailed rebuttal. 

2017

A Python Developers Survey towards the end of 2017 done by JetBrains finds that 75% of respondents use Python 3. In the domain of data science, adoption is higher at 80%. 

Apr  
2020

The last major version of Python 2.7 is expected to be released in April. Following this, Python 3 will be the only one supported for bugs and security fixes.