Section author: Robert Nikutta <>

Version: 20211119

4.3. Python 3 vs Python 2

Support for Python 2 at Data Lab ended in October 2020. Python 3 is now mature, fast, and the default Python version for the foreseeable future. While all notebooks curated at Astro Data Lab use Python 3, some users may be still using older Python 2 versions. This page is meant to provide some guidance in how to make these older notebooks compatible with Python 3 and how to continue running them at Data Lab.

The required changes are likely minor. If after reading through this guide you still find yourself unable to run your notebook, please contact the team at . We are here to help!

4.3.2. No more xrange(), use range() instead

Python 2 supported both range() and xrange() functions to construct a sequence of integers. range(10,16) for instance returned a list of integers [10,11,12,13,14,15], while xrange(10,16) returned an object that knew how to generate the next integer between 10 and 15. range() materialized the entire sequence into memory (which can be a lot of data, if the MIN and MAX values are far apart), while xrange() only generated one number at a time (much more memory efficient, but slower).

In Python 3 there is no more xrange(), and range() is the object that knows how to make a list of integers. Plus, it’s now fast. That is, always use range(10,16), and if you need the full list at once, wrap the command inside a list() function, i.e. list(range(10,16)) --> [10,11,12,13,14,15].

4.3.3. Division operators

This one is potentially dangerous if your Python 2 notebook relied on integer division. In Python 2 the division operator /, when applied to integers, returned the result of integer division, i.e. it dropped the remainder:

# Python 2
10 / 3

In Python 3, the same expression returns a float:

# Python 3
10 / 3

To achieve a floating point result in Python 2, one had to cast one of the operands as float:

# Python 2
10 / 3.

# or
10 / float(3)

Python 3 does the casting automatically.

If you want integer division on Python 3, use the // operator:

# Python 3 integer division
10 // 3

4.3.4. Strings and bytes

The implicit type of bytes in Python 2 is str, but in Python 3 str and bytes are different:

# Python 2: str and bytes are the same
type("Hello"), type(b"Hello")
(str, str)

# Python 3: str and bytes are different
type("Hello"), type(b"Hello")
(str, bytes)

If you need to convert a string to bytes in Python 3:

# Python 3
b"hello" --> is bytes
"Hello".encode() --> same

And if you need to convert a bytes sequence to str:

# Python 3
foo = b"Hello"


4.3.5. More documentation of differences between Python 2 and 3

Many more examples and guides on the differences between Python 2 and 3 are described in many places on the internet. Learn about differences in handling exceptions, new-style string formatting, iterator methods, renamed modules, and much more, for instance here: