Python Language Incompatibilities moving from Python 2 to Python 3 Unpacking Iterables

Help us to keep this website almost Ad Free! It takes only 10 seconds of your time:
> Step 1: Go view our video on YouTube: EF Core Bulk Insert
> Step 2: And Like the video. BONUS: You can also share it!

Example

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, you cannot have two *s for the same iterable in an assignment - it wouldn't know how many elements go 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.



Got any Python Language Question?