Python Language


Incompatibilities between Python 2 and Python 3 All Versions

Python 3.x

3.0
3.1
3.2
3.3
3.4
3.5
3.6

Python 2.x

2.0
2.1
2.2
2.3
2.4
2.5
2.6
2.7

This draft deletes the entire topic.

Introduction

Unlike most languages, Python supports two major versions. Since 2008 when Python 3 was released, many have made the transition, while many have not. In order to understand both, this section covers the important differences between Python 2 and Python 3.

expand all collapse all

Examples

  • 244

    The standard division symbol (/) operates differently in Python 3 and Python 2 when applied to integers.

    When dividing an integer by another integer in Python 3, the division operation x / y represents a true division and produces a floating point result. In Python 3 the / maps to __truediv__. Meanwhile, the same operation in Python 2 represents a classic division that rounds the result down toward negative infinity (also known as taking the floor).

    For example:

    CodePython 2 outputPython 3 output
    3 / 211.5
    2 / 300.6666666666666666
    -3 / 2-2-1.5

    The rounding-towards-zero behavior was deprecated in Python 2.2, but remains in Python 2.7 for the sake of backward compatibility and was removed in Python 3.

    Note: To get a float result (without floor rounding) we can specify one of the operands with the decimal point. The above example of 2/3 which gives 0 in Python 2 shall be used as 2 / 3.0 or 2.0 / 3 or 2.0/3.0 to get `0.6666666666666666.'


    There is also the floor division operator (//), which works the same way in both versions: it rounds down to the nearest integer (i.e., works the same as the / operator in Python 2). In Python 3 the // operator maps to __floordiv__.

    CodePython 2 outputPython 3 output
    3 // 211
    2 // 300
    -3 // 2-2-2

    One can explicitly enforce true division or floor division using native functions in the operator module:

    from operator import truediv, floordiv
    assert truediv(10, 8) == 1.25                              # equiv. `/` in Python 3
    assert floordiv(10, 8) == 1                                # equiv. `/` in Python 2  or `//`
    

    While clear and explicit, using operator functions for every division can be tedious. Changing the behavior of the / operator will often be preferred. A common practice is to eliminate typical division behavior by adding from __future__ import division as the first statement in each module:

    # needs to be the first statement in a module
    from __future__ import division
    
    CodePython 2 outputPython 3 output
    3 / 21.51.5
    2 / 30.66666666666666660.6666666666666666
    -3 / 2-1.5-1.5

    from __future__ import division guarantees that the / operator represents actual division and only within the modules that contain the __future__ import, so there are no compelling reasons for not enabling it in all new modules.

    Note: Some other programming languages use rounding toward zero (truncation) rather than rounding down toward negative infinity as Python does (i.e. in those languages -3 / 2 == -1). This behavior may create confusion when porting or comparing code.


    Note on float operands: As an alternative to from __future__ import division, one could use the usual division symbol / and ensure that at least one of the operands is a float: 3 / 2.0 == 1.5. However, this can be considered bad practice. It is just too easy to write average = sum(items) / len(items) and forget to cast one of the arguments to float. Moreover, such cases may frequently evade notice during testing, e.g., if you test on an array containing floats but receive an array of ints in production. Additionally, if the same code is used in Python 3, programs that expect 3 / 2 == 1 to be True will not work correctly.

    See PEP 238 for more detailed rationale why the division operator was changed in Python 3 and why old-style division should be avoided.


    See the Simple Math topic for more about division.

  • 113
    Python 3.x3.0

    In Python 3, you can unpack an iterable without knowing the exact number of items in it, and even have a variable hold the end of the iterable. For that, you provide a variable that may collect a list of values. This is done by placing an asterisk before the name. For example, unpacking a list:

    first, second, *tail, last = [1, 2, 3, 4, 5]
    print(first)
    # Out: 1
    print(second)
    # Out: 2
    print(tail)
    # Out: [3, 4]
    print(last)
    # Out: 5
    

    Note: When using the *variable syntax, the variable will always be a list, even if the original type wasn't a list. It may contain zero or more elements depending on the number of elements in the original list.

    first, second, *tail, last = [1, 2, 3, 4]
    print(tail)
    # Out: [3]
    
    first, second, *tail, last = [1, 2, 3]
    print(tail)
    # Out: []
    print(last)
    # Out: 3
    

    Similarly, unpacking a str:

    begin, *tail = "Hello"
    print(begin)
    # Out: 'H'
    print(tail)
    # Out: ['e', 'l', 'l', 'o']
    

    Example of unpacking a date; _ is used in this example as a throwaway variable (we are interested only in year value):

    person = ('John', 'Doe', (10, 16, 2016))
    *_, (*_, year_of_birth) = person
    print(year_of_birth)
    # Out: 2016
    

    It is worth mentioning that, since * eats up a variable number of items in the given sequence, assignments do not allow two *s for the same expression — it wouldn't know how many elements went into the first unpacking, and how many in the second:

    *head, *tail = [1, 2]
    # Out: SyntaxError: two starred expressions in assignment
    
    Python 3.x3.5

    So far we have discussed unpacking in assignments. * and ** were extended in Python 3.5. It's now possible to have several unpacking operations in one expression:

    {*range(4), 4, *(5, 6, 7)}
    # Out: {0, 1, 2, 3, 4, 5, 6, 7}
    
    Python 2.x2.0

    It is also possible to unpack an iterable into function arguments:

    iterable = [1, 2, 3, 4, 5]
    print(iterable)
    # Out: [1, 2, 3, 4, 5]
    print(*iterable)
    # Out: 1 2 3 4 5
    
    Python 3.x3.5

    Unpacking a dictionary uses two adjacent stars ** (PEP 448):

    tail = {'y': 2, 'z': 3}
    {'x': 1, **tail}
     # Out: {'x': 1, 'y': 2, 'z': 3}
    

    This allows for both overriding old values and merging dictionaries.

    dict1 = {'x': 1, 'y': 1}
    dict2 = {'y': 2, 'z': 3}
    {**dict1, **dict2}
    # Out: {'x': 1, 'y': 2, 'z': 3}
    
    Python 3.x3.0

    Python 3 removed tuple unpacking in functions. Hence the following doesn't work in Python 3

    # Works in Python 2, but syntax error in Python 3:
    map(lambda (x, y): x + y, zip(range(5), range(5)))
    # Same is true for non-lambdas:
    def example((x, y)):
        pass
    
    # Works in both Python 2 and Python 3:
    map(lambda x: x[0] + x[1], zip(range(5), range(5)))
    # And non-lambdas, too:
    def working_example(x_y):
        x, y = x_y
        pass
    

    See PEP 3113 for detailed rationale.

  • 99
    Python 2.x2.7

    In Python 2 there are two types of strings: bytes (str) and text (unicode).

    In Python 2, an object of type str is always a byte sequence, but is commonly used for both text and binary data.

    A string literal is interpreted as a byte string.

    s = 'Cafe'    # type(s) == str
    

    There are two exceptions: You can define a Unicode (text) literal explicitly by prefixing the literal with u:

    s = u'Café'   # type(s) == unicode
    b = 'Lorem ipsum'  # type(b) == str
    

    Alternatively, you can specify that a whole module's string literals should create Unicode (text) literals:

    from __future__ import unicode_literals
    
    s = 'Café'   # type(s) == unicode
    b = 'Lorem ipsum'  # type(b) == unicode
    

    In order to check whether your variable is a string (either Unicode or a byte string), you can use:

    isinstance(s, basestring)
    
    Python 3.x3.0

    In Python 3, the str type is a Unicode text type.

    s = 'Cafe'           # type(s) == str
    s = 'Café'           # type(s) == str (note the accented trailing e)
    

    Additionally, Python 3 added a bytes object, suitable for binary "blobs" or writing to encoding-independent files. To create a bytes object, you can prefix b to a string literal or call the string's encode method:

    # Or, if you really need a byte string:
    s = b'Cafe'          # type(s) == bytes
    s = 'Café'.encode()  # type(s) == bytes
    

    To test whether a value is a string, use:

    isinstance(s, str)
    
    Python 3.x3.3

    It is also possible to prefix string literals with a u prefix to ease compatibility between Python 2 and Python 3 code bases. Since, in Python 3, all strings are Unicode by default, prepending a string literal with u has no effect:

    u'Cafe' ==  'Cafe' 
    

    Note that you must encode a Python 3 text (str) object to convert it into a bytes representation of that text. The default encoding of this method is UTF-8.

    You can use decode to ask a bytes object for what Unicode text it represents:

    >>> b.decode()
    'Café'
    
    Python 2.x2.6

    While the bytes type exists in both Python 2 and 3, the unicode type only exists in Python 2. To use Python 3's implicit Unicode strings in Python 2, add the following to the top of your code file:

    from __future__ import unicode_literals
    print(repr("hi"))
    # u'hi'
    
    Python 3.x3.0

    Another important difference is that indexing bytes in Python 3 results in an int output like so:

    b"abc"[0] == 97
    

    Whilst slicing in a size of one results in a length 1 bytes object:

    b"abc"[0:1] == b"a"
    

    In addition, Python 3 fixes some unusual behavior with unicode, i.e. reversing byte strings in Python 2. For example, the following issue is resolved:

    # -*- coding: utf8 -*-
    print("Hi, my name is Łukasz Langa.")
    print(u"Hi, my name is Łukasz Langa."[::-1])
    print("Hi, my name is Łukasz Langa."[::-1])
    
    # Output in Python 2
    # Hi, my name is Łukasz Langa.
    # .agnaL zsakuŁ si eman ym ,iH
    # .agnaL zsaku�� si eman ym ,iH
    
    # Output in Python 3
    # Hi, my name is Łukasz Langa.
    # .agnaL zsakuŁ si eman ym ,iH
    # .agnaL zsakuŁ si eman ym ,iH
    
Please consider making a request to improve this example.

Syntax

Syntax

Parameters

Parameters

Remarks

There are currently two supported versions of Python: 2.7 (Python 2) and 3.6 (Python 3). Additionally versions 3.3 and 3.4 receive security updates in source format.

Python 2.7 is backwards-compatible with most earlier versions of Python, and can run Python code from most 1.x and 2.x versions of Python unchanged. It is broadly available, with an extensive collection of packages. It is also considered deprecated by the CPython developers, and receives only security and bug-fix development. The CPython developers intend to abandon this version of the language in 2020.

According to Python Enhancement Proposal 373 there are no planned future releases of Python 2 after 25 June 2016, but bug fixes and security updates will be supported until 2020. (It doesn't specify what exact date in 2020 will be the sunset date of Python 2.)

Python 3 intentionally broke backwards-compatibility, to address concerns the language developers had with the core of the language. Python 3 receives new development and new features. It is the version of the language that the language developers intend to move forward with.

Over the time between the initial release of Python 3.0 and the current version, some features of Python 3 were back-ported into Python 2.6, and other parts of Python 3 were extended to have syntax compatible with Python 2. Therefore it is possible to write Python that will work on both Python 2 and Python 3, by using future imports and special modules (like six).

Future imports have to be at the beginning of your module:

from __future__ import print_function
# other imports and instructions go after __future__
print('Hello world')

For further information on the __future__ module, see the relevant page in the Python documentation.

The 2to3 tool is a Python program that converts Python 2.x code to Python 3.x code, see also the Python documentation.

The package six provides utilities for Python 2/3 compatibility:

  • unified access to renamed libraries
  • variables for string/unicode types
  • functions for method that got removed or has been renamed

A reference for differences between Python 2 and Python 3 can be found here.

Still have a question about Incompatibilities between Python 2 and Python 3? Ask Question

Topic Outline